agent-switchboard 2.2.2__tar.gz → 2.4.0__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.
Files changed (303) hide show
  1. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/.github/workflows/ci.yml +100 -35
  2. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/.gitignore +6 -0
  3. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/ARCS.md +8 -3
  4. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/PKG-INFO +60 -11
  5. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/README.md +59 -10
  6. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/demo/chess.sh +4 -4
  7. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/demo/run.sh +4 -4
  8. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/claude-code.md +167 -21
  9. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/codex-cli.md +19 -13
  10. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/concepts.md +16 -0
  11. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/quickstart.md +2 -2
  12. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/extras/session-capsule/README.md +18 -0
  13. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/pyproject.toml +1 -1
  14. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/ROADMAP.md +366 -5
  15. agent_switchboard-2.4.0/roadmap/items/a-drain-that-retries-forever-never-escalates.yaml +70 -0
  16. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/ci-workspace-is-public.yaml +2 -1
  17. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/cross-key-rendezvous.yaml +16 -0
  18. agent_switchboard-2.4.0/roadmap/items/discovery-is-uneven-and-delivery-is-unknowable.yaml +80 -0
  19. agent_switchboard-2.4.0/roadmap/items/first-contact-needs-a-key-it-cannot-have.yaml +62 -0
  20. agent_switchboard-2.4.0/roadmap/items/inbox-consumes-what-it-cannot-open.yaml +51 -0
  21. agent_switchboard-2.4.0/roadmap/items/rootless-warning-false-positive.yaml +81 -0
  22. agent_switchboard-2.4.0/site/PRINCIPLES.md +536 -0
  23. agent_switchboard-2.4.0/site/check-quotes.py +223 -0
  24. agent_switchboard-2.4.0/site/clips/collision.txt +43 -0
  25. agent_switchboard-2.4.0/site/clips/crash.txt +31 -0
  26. agent_switchboard-2.4.0/site/demo.cast +41 -0
  27. agent_switchboard-2.4.0/site/design/BRIEF.md +332 -0
  28. agent_switchboard-2.4.0/site/design/Main.dc.html +449 -0
  29. agent_switchboard-2.4.0/site/design/Mobile.dc.html +24 -0
  30. agent_switchboard-2.4.0/site/design/canvas.json +12 -0
  31. agent_switchboard-2.4.0/site/design/capture-viewer.sh +73 -0
  32. agent_switchboard-2.4.0/site/design/img/README.md +62 -0
  33. agent_switchboard-2.4.0/site/design/img/island-play.jpg +0 -0
  34. agent_switchboard-2.4.0/site/design/img/viewer-phone.jpg +0 -0
  35. agent_switchboard-2.4.0/site/design/og-card.html +83 -0
  36. agent_switchboard-2.4.0/site/design/render-og.py +77 -0
  37. agent_switchboard-2.4.0/site/img/README.md +36 -0
  38. agent_switchboard-2.4.0/site/img/apple-touch-icon.png +0 -0
  39. agent_switchboard-2.4.0/site/img/favicon-16.png +0 -0
  40. agent_switchboard-2.4.0/site/img/favicon-32.png +0 -0
  41. agent_switchboard-2.4.0/site/img/favicon.svg +11 -0
  42. agent_switchboard-2.4.0/site/img/og.jpg +0 -0
  43. agent_switchboard-2.4.0/site/index.html +1090 -0
  44. agent_switchboard-2.4.0/site/privacy.html +134 -0
  45. agent_switchboard-2.4.0/site/record-collision.sh +48 -0
  46. agent_switchboard-2.4.0/site/record-crash.sh +61 -0
  47. agent_switchboard-2.4.0/site/record-demo.py +78 -0
  48. agent_switchboard-2.4.0/site/stamp-version.py +92 -0
  49. agent_switchboard-2.4.0/site/terms.html +127 -0
  50. agent_switchboard-2.4.0/site/vercel.json +40 -0
  51. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/__init__.py +1 -1
  52. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/claude_session.py +57 -6
  53. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/cli.py +418 -59
  54. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/client.py +134 -14
  55. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/config.py +91 -7
  56. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/desktop.py +8 -3
  57. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/invite.py +85 -0
  58. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/knownrooms.py +1 -0
  59. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/mcp_server.py +132 -21
  60. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/rendezvous.py +88 -0
  61. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/rooms.py +54 -4
  62. agent_switchboard-2.4.0/src/switchboard/skill/history/027-SKILL.md +332 -0
  63. agent_switchboard-2.4.0/src/switchboard/skill/switchboard-coordinate/SKILL.md +403 -0
  64. agent_switchboard-2.4.0/src/switchboard/stash.py +169 -0
  65. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/testing.py +10 -2
  66. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/conftest.py +49 -0
  67. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_claude_session.py +65 -7
  68. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_cli_config.py +64 -0
  69. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_cli_init.py +76 -2
  70. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_config.py +93 -0
  71. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_crypto.py +11 -0
  72. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_drill.py +10 -2
  73. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_invite.py +130 -1
  74. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_mcp.py +55 -0
  75. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_rendezvous.py +244 -0
  76. agent_switchboard-2.4.0/tests/test_sending_opens_a_conversation.py +301 -0
  77. agent_switchboard-2.4.0/tests/test_stash.py +124 -0
  78. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_whisper.py +107 -8
  79. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_workflow_token.py +28 -4
  80. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/.dockerignore +0 -0
  81. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/.github/workflows/deploy.yml +0 -0
  82. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/.github/workflows/pages.yml +0 -0
  83. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/.github/workflows/publish-viewer.yml +0 -0
  84. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/.github/workflows/publish.yml +0 -0
  85. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/.github/workflows/roadmap.yml +0 -0
  86. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/AGENTS.md +0 -0
  87. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/CONTRIBUTING.md +0 -0
  88. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/Dockerfile +0 -0
  89. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/LICENSE +0 -0
  90. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/demo/README.md +0 -0
  91. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docker-compose.yml +0 -0
  92. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/adaptive-timing.md +0 -0
  93. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/api.md +0 -0
  94. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/deployment.md +0 -0
  95. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/drills.md +0 -0
  96. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/encryption.md +0 -0
  97. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/environments.md +0 -0
  98. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/images/viewer.png +0 -0
  99. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/layers.md +0 -0
  100. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/managed-hub.md +0 -0
  101. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/model.md +0 -0
  102. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/seam.md +0 -0
  103. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/testing.md +0 -0
  104. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/upgrading.md +0 -0
  105. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/viewer.md +0 -0
  106. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/docs/why-this-exists.md +0 -0
  107. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/examples/coordinated_worker.py +0 -0
  108. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/extras/session-capsule/cc.sh +0 -0
  109. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/extras/session-capsule/claude_session_capsule.py +0 -0
  110. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/extras/viewer/README.md +0 -0
  111. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/extras/viewer/pyproject.toml +0 -0
  112. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/extras/viewer/switchboard_viewer/__init__.py +0 -0
  113. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/extras/viewer/switchboard_viewer/__main__.py +0 -0
  114. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/extras/viewer/switchboard_viewer/viewer.py +0 -0
  115. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/extras/viewer/switchboard_viewer/web/index.html +0 -0
  116. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/extras/viewer/switchboard_viewer/web/render.js +0 -0
  117. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/extras/viewer/switchboard_viewer/web/switchboard-open.js +0 -0
  118. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/extras/viewer/switchboard_viewer/web/switchboard-room.js +0 -0
  119. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/README.md +0 -0
  120. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/arcs/distribution.yaml +0 -0
  121. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/arcs/hub-boundary.yaml +0 -0
  122. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/arcs/setup-and-first-run.yaml +0 -0
  123. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/arcs/ttl-ceilings.yaml +0 -0
  124. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/a-lobby-derived-from-the-key.yaml +0 -0
  125. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/abuse-control-after-authorization.yaml +0 -0
  126. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/automatic-session-checkpoints.yaml +0 -0
  127. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/board-ttl-ceiling.yaml +0 -0
  128. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/clients-that-cannot-post.yaml +0 -0
  129. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/connect-failure-message.yaml +0 -0
  130. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/every-silent-failure-looks-like-a-quiet-room.yaml +0 -0
  131. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/hooks-warning-false-positive.yaml +0 -0
  132. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/hub-origin-reachable-bypassing-the-edge.yaml +0 -0
  133. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/identity-rebinds-on-branch-change.yaml +0 -0
  134. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/init-writes-rooms-file.yaml +0 -0
  135. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/intermittent-suite-failure.yaml +0 -0
  136. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/joining-agent-sees-empty-inbox.yaml +0 -0
  137. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/known-rooms-address-book.yaml +0 -0
  138. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/one-resolved-context-across-surfaces.yaml +0 -0
  139. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/presence-ttl-is-not-one-size.yaml +0 -0
  140. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/provisioned-token-is-stale-and-nothing-says-so.yaml +0 -0
  141. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/publish-hub-container-image.yaml +0 -0
  142. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/read-only-rooms.yaml +0 -0
  143. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/robots-policy-for-public-hosts.yaml +0 -0
  144. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/roles-and-authority-between-agents.yaml +0 -0
  145. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/seal-agent-meta.yaml +0 -0
  146. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/selective-wake-for-the-listener.yaml +0 -0
  147. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/stale-resolver-references.yaml +0 -0
  148. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/stale-token-in-session-env.yaml +0 -0
  149. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/standing-checks-that-nothing-runs.yaml +0 -0
  150. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/timing-cold-start-in-ephemeral-environments.yaml +0 -0
  151. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/ttl-clamped-silently.yaml +0 -0
  152. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/unread-dms-not-shown-outside-mcp.yaml +0 -0
  153. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/roadmap/items/write-parity-across-surfaces.yaml +0 -0
  154. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/scripts/deploy.sh +0 -0
  155. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/auth.py +0 -0
  156. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/crypto.py +0 -0
  157. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/drill.py +0 -0
  158. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/guidance.py +0 -0
  159. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/handoff.py +0 -0
  160. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/holds.py +0 -0
  161. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/load.py +0 -0
  162. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/notify.py +0 -0
  163. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/peers.py +0 -0
  164. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/scripts/wake-on-message.sh +0 -0
  165. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/server.py +0 -0
  166. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/signing.py +0 -0
  167. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/001-SKILL.md +0 -0
  168. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/002-SKILL.md +0 -0
  169. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/003-SKILL.md +0 -0
  170. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/004-SKILL.md +0 -0
  171. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/005-SKILL.md +0 -0
  172. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/006-SKILL.md +0 -0
  173. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/007-SKILL.md +0 -0
  174. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/008-SKILL.md +0 -0
  175. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/009-SKILL.md +0 -0
  176. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/010-SKILL.md +0 -0
  177. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/011-SKILL.md +0 -0
  178. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/012-SKILL.md +0 -0
  179. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/013-SKILL.md +0 -0
  180. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/014-SKILL.md +0 -0
  181. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/015-SKILL.md +0 -0
  182. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/016-SKILL.md +0 -0
  183. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/017-SKILL.md +0 -0
  184. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/018-SKILL.md +0 -0
  185. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/019-SKILL.md +0 -0
  186. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/020-SKILL.md +0 -0
  187. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/021-SKILL.md +0 -0
  188. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/022-SKILL.md +0 -0
  189. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/023-SKILL.md +0 -0
  190. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/024-SKILL.md +0 -0
  191. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/skill/history/025-SKILL.md +0 -0
  192. /agent_switchboard-2.2.2/src/switchboard/skill/switchboard-coordinate/SKILL.md → /agent_switchboard-2.4.0/src/switchboard/skill/history/026-SKILL.md +0 -0
  193. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/spec.py +0 -0
  194. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/store.py +0 -0
  195. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/timing.py +0 -0
  196. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/src/switchboard/writekey.py +0 -0
  197. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/README.md +0 -0
  198. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/__init__.py +0 -0
  199. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/analysis.py +0 -0
  200. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/economy.py +0 -0
  201. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/flow.py +0 -0
  202. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/llm.py +0 -0
  203. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/manager.py +0 -0
  204. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/report.py +0 -0
  205. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/run.py +0 -0
  206. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/tier1.json +0 -0
  207. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/tier1_labour.json +0 -0
  208. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/tier1_rounds.json +0 -0
  209. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/tier2_seed1_bound.json +0 -0
  210. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/tier2_seed1_built.json +0 -0
  211. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/tier2_seed1_free.json +0 -0
  212. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/tier2_seed1_paid.json +0 -0
  213. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/tier2_seed1_spend.json +0 -0
  214. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/tier2_seed1_told.json +0 -0
  215. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/tier2_seed41_bound.json +0 -0
  216. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter/traders.py +0 -0
  217. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter_experiment.py +0 -0
  218. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/barter_llm_experiment.py +0 -0
  219. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_harness.py +0 -0
  220. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/RESULTS.md +0 -0
  221. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/prompt_A_s31337.txt +0 -0
  222. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/prompt_A_s4242.txt +0 -0
  223. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/prompt_A_s7777.txt +0 -0
  224. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/prompt_B_s31337.txt +0 -0
  225. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/prompt_B_s4242.txt +0 -0
  226. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/prompt_B_s7777.txt +0 -0
  227. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/prompt_C_s31337.txt +0 -0
  228. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/prompt_C_s4242.txt +0 -0
  229. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/prompt_C_s7777.txt +0 -0
  230. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_haiku_A_s31337.json +0 -0
  231. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_haiku_A_s4242.json +0 -0
  232. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_haiku_A_s7777.json +0 -0
  233. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_haiku_B_s31337.json +0 -0
  234. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_haiku_B_s4242.json +0 -0
  235. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_haiku_B_s7777.json +0 -0
  236. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_haiku_C_s31337.json +0 -0
  237. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_haiku_C_s4242.json +0 -0
  238. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_haiku_C_s7777.json +0 -0
  239. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_opus_A_s31337.json +0 -0
  240. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_opus_A_s4242.json +0 -0
  241. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_opus_A_s7777.json +0 -0
  242. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_opus_B_s31337.json +0 -0
  243. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_opus_B_s4242.json +0 -0
  244. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_opus_B_s7777.json +0 -0
  245. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_opus_C_s31337.json +0 -0
  246. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_opus_C_s4242.json +0 -0
  247. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_opus_C_s7777.json +0 -0
  248. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_sonnet_A_s31337.json +0 -0
  249. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_sonnet_A_s4242.json +0 -0
  250. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_sonnet_A_s7777.json +0 -0
  251. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_sonnet_B_s31337.json +0 -0
  252. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_sonnet_B_s4242.json +0 -0
  253. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_sonnet_B_s7777.json +0 -0
  254. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_sonnet_C_s31337.json +0 -0
  255. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_sonnet_C_s4242.json +0 -0
  256. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_pilot/response_sonnet_C_s7777.json +0 -0
  257. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/tier2_run.py +0 -0
  258. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/experiments/timing_experiment.py +0 -0
  259. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_api.py +0 -0
  260. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_arrive.py +0 -0
  261. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_auth.py +0 -0
  262. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_barter.py +0 -0
  263. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_barter_llm.py +0 -0
  264. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_cli_board.py +0 -0
  265. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_cli_checkin.py +0 -0
  266. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_cli_global_flags.py +0 -0
  267. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_cli_serve.py +0 -0
  268. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_cli_session.py +0 -0
  269. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_cli_timing.py +0 -0
  270. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_client_invite.py +0 -0
  271. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_cors_write_headers.py +0 -0
  272. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_dash_ids.py +0 -0
  273. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_declare.py +0 -0
  274. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_deployment.py +0 -0
  275. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_desktop.py +0 -0
  276. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_evening_replayed.py +0 -0
  277. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_example_viewer.py +0 -0
  278. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_failure_messages.py +0 -0
  279. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_handoff.py +0 -0
  280. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_help.py +0 -0
  281. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_isolated_hub.py +0 -0
  282. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_known_rooms.py +0 -0
  283. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_leave_a_ghost.py +0 -0
  284. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_load.py +0 -0
  285. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_lobby.py +0 -0
  286. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_mcp_session.py +0 -0
  287. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_notify.py +0 -0
  288. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_rooms.py +0 -0
  289. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_spec.py +0 -0
  290. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_store.py +0 -0
  291. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_surface_parity.py +0 -0
  292. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_testing.py +0 -0
  293. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_tier2_harness.py +0 -0
  294. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_timing.py +0 -0
  295. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_timing_experiment.py +0 -0
  296. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_transient_failures.py +0 -0
  297. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_version.py +0 -0
  298. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_wake_listener.py +0 -0
  299. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_web_invite.py +0 -0
  300. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_web_page.py +0 -0
  301. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_web_reader.py +0 -0
  302. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_web_snapshot.py +0 -0
  303. {agent_switchboard-2.2.2 → agent_switchboard-2.4.0}/tests/test_write_keys.py +0 -0
@@ -143,13 +143,19 @@ jobs:
143
143
  # success is the failure being fixed.
144
144
  browser:
145
145
  runs-on: ubuntu-latest
146
- # The only job here that installs system packages, and the only one that
147
- # has hung. On #138 `playwright install --with-deps` sat in apt for 71
148
- # minutes; GitHub's default job timeout is six HOURS, so nothing would have
149
- # said so until the afternoon was gone, and the PR reads as `unstable` —
150
- # not red, not green — the whole time. Ten minutes is roughly five times
151
- # the step's normal cost, so it bounds the hang without failing a slow
152
- # mirror.
146
+ # This job used to install system packages, and it was the only one that
147
+ # ever hung or failed on something outside the repo. On #138
148
+ # `playwright install --with-deps` sat in apt for 71 minutes; on #251 the
149
+ # same step failed twice with a Hash Sum mismatch fetching Google's Chrome
150
+ # index, because `--with-deps` adds apt — and therefore dl.google.com — to
151
+ # the critical path of a job that only needs a browser binary.
152
+ #
153
+ # ubuntu-latest already ships the shared libraries Chromium links against,
154
+ # so the deps step is gone. If that ever stops being true, Chromium fails
155
+ # to launch and the tests below go red — loudly, and without a skip, which
156
+ # the last step enforces.
157
+ #
158
+ # The timeout stays: it bounded the hang before and costs nothing.
153
159
  timeout-minutes: 10
154
160
  steps:
155
161
  - uses: actions/checkout@v4
@@ -157,7 +163,7 @@ jobs:
157
163
  with:
158
164
  python-version: "3.12"
159
165
  - run: pip install -e '.[dev]' playwright
160
- - run: playwright install --with-deps chromium
166
+ - run: playwright install chromium
161
167
  - name: the page, in a browser — and nothing may skip
162
168
  # `-p no:randomly` keeps the summary line stable to grep. The skip
163
169
  # check is the whole point of the job: if the browser fixture ever
@@ -170,6 +176,27 @@ jobs:
170
176
  exit 1
171
177
  fi
172
178
 
179
+ # The landing page quotes real terminal output. Until #277 the largest of
180
+ # those blocks was generated from site/demo.cast, so it could not drift;
181
+ # that generator is gone and the quotes are now placed by hand, which means
182
+ # a change to the CLI's output can leave the page showing a line no run
183
+ # prints any more. site/PRINCIPLES.md principle 4 is the whole reason this
184
+ # page is worth anything, so it is checked rather than trusted.
185
+ #
186
+ # Offline on purpose: it reads only files in this repository. The island
187
+ # boards are quoted from another host and are checked by hand with
188
+ # `python3 site/check-quotes.py --online`, because a CI run should not go
189
+ # red over somebody else's uptime. Stdlib only, so there is nothing to
190
+ # install.
191
+ site-quotes:
192
+ runs-on: ubuntu-latest
193
+ steps:
194
+ - uses: actions/checkout@v4
195
+ - uses: actions/setup-python@v5
196
+ with:
197
+ python-version: "3.12"
198
+ - run: python3 site/check-quotes.py
199
+
173
200
  docker:
174
201
  runs-on: ubuntu-latest
175
202
  steps:
@@ -184,48 +211,86 @@ jobs:
184
211
  curl -sf http://127.0.0.1:8787/health | grep -q '"ok":true'
185
212
  docker rm -f swb
186
213
 
187
- # Dogfooding: this CI run announces itself on the same hub the rest of
188
- # this project coordinates over, same as local/cloud agents do via the
189
- # SessionStart hook `init` installs (see cli.py's _SESSION_START_CMD).
190
- # It announces into its own workspace rather than the interactive one, so a
191
- # CI run never shows up in the middle of a human session's peers.
214
+ # A smoke test against the real hub, not a notice board.
215
+ #
216
+ # This used to announce into a fixed room so a CI run appeared beside the
217
+ # human sessions. That room's identifier sat in this file in plain text, and
218
+ # since #73 the hub does no authorization — reaching a room IS knowing its
219
+ # identifier — so it was the one published room in a repository whose own
220
+ # .gitignore refuses to commit .mcp.json for the same reason.
192
221
  #
193
- # The token is read from MANAGED_HUB_TOKEN in the checkout, the same way
194
- # deploy.yml reads the value it starts the hub with. That is the whole point:
195
- # a private second copy in `secrets.SWITCHBOARD_TOKEN` drifted from the hub's
196
- # own token and locked this job out for a day without failing a build (#96).
197
- # Since #76 a token admits a caller to the hub and scopes nothing, so there
198
- # is nothing for a secret copy to protect that the published one does not.
222
+ # The fix is not a secret. Nobody was reading what CI announced, so the room
223
+ # does not need to persist: the job mints its own, uses it, and drops it. No
224
+ # identifier to leak, no key to rotate, no secret withheld from a fork's pull
225
+ # request — and the job now behaves identically for a contributor as it does
226
+ # on main.
199
227
  #
200
- # Never gates the rest of CI, and never fails silently either: the announce
201
- # cannot break a build, but a failure is reported as a warning on the run
202
- # instead of one line of stderr in a green job.
228
+ # What it buys beyond safety: the old job could not fail. It warned and
229
+ # exited green, so a client that could not reach the hub at all still showed
230
+ # a passing check. This one mints, announces, and reads the roster back,
231
+ # asserting the agent it just created is there. That is the whole client
232
+ # path — keygen, seal, POST, GET, decrypt — against the live hub on every
233
+ # run, and it goes red when any of it breaks.
234
+ #
235
+ # The token still comes from MANAGED_HUB_TOKEN in the checkout rather than a
236
+ # secret: a private copy drifted from the hub's own token and locked this job
237
+ # out for a day without failing a build (#96). Since #76 a token admits a
238
+ # caller and scopes nothing, so a secret copy protects nothing the published
239
+ # one does not.
203
240
  register-switchboard:
241
+ # Never on a pull request. This is the one job that talks to a server
242
+ # somebody has to keep up, and a hub reboot must not turn a contributor's
243
+ # PR red for a reason that has nothing to do with their change — red for
244
+ # no reason is how people learn to ignore red.
245
+ #
246
+ # On main it gates, which is the point: a check that cannot fail is not a
247
+ # check, and the old one warned and exited green even when the client
248
+ # could not reach the hub at all.
249
+ if: github.event_name != 'pull_request'
204
250
  runs-on: ubuntu-latest
251
+ timeout-minutes: 5
205
252
  steps:
206
253
  - uses: actions/checkout@v4
207
254
  - uses: actions/setup-python@v5
208
255
  with:
209
256
  python-version: "3.12"
210
257
  - run: pip install -e .
211
- - name: Announce this CI run to the hub
258
+ - name: Mint a room, announce into it, and read it back
212
259
  env:
213
260
  SWITCHBOARD_URL: https://switchboard.lucille-ai.com
214
- SWITCHBOARD_WORKSPACE: w_gAbpTxVh-Jl0pjx0Hnqupw
261
+ SWITCHBOARD_AGENT_ID: ci-${{ github.run_id }}-${{ github.run_attempt }}
215
262
  run: |
263
+ set -euo pipefail
264
+
216
265
  SWITCHBOARD_TOKEN="$(sed -n 's/^MANAGED_HUB_TOKEN = "\([^"]*\)".*/\1/p' \
217
266
  src/switchboard/config.py | head -1)"
218
- export SWITCHBOARD_TOKEN
219
267
  if [ -z "$SWITCHBOARD_TOKEN" ]; then
220
- echo "::warning title=switchboard::MANAGED_HUB_TOKEN not found in" \
221
- "src/switchboard/config.py — this CI run was not announced"
222
- exit 0
268
+ echo "::error title=switchboard::MANAGED_HUB_TOKEN not found in" \
269
+ "src/switchboard/config.py"
270
+ exit 1
223
271
  fi
224
- if ! out="$(switchboard -q register --kind ci -c build \
225
- --task "${{ github.event_name }} ${{ github.ref_name }}@${{ github.sha }}" 2>&1)"; then
226
- # Last line only: an auth failure is one line, but a connection
227
- # failure is a whole httpx traceback (#88), and a warning is a
228
- # one-line surface. The last line is the diagnosis in both cases.
229
- echo "::warning title=switchboard::announce failed:" \
230
- "$(printf '%s' "${out:-no output}" | tail -n 1)"
272
+ export SWITCHBOARD_TOKEN
273
+
274
+ # A room of its own, thrown away when the job ends. Everything in it
275
+ # expires on its own anyway — presence in two minutes.
276
+ eval "$(switchboard keygen --no-input | sed 's/^/export /')"
277
+
278
+ MARK="${{ github.event_name }} ${{ github.ref_name }}@${{ github.sha }}"
279
+ switchboard -q announce --kind ci -c build --task "$MARK"
280
+
281
+ # The assertion, and it is deliberately on the task rather than on
282
+ # the agent id. Ids are scrambled before they reach the hub, so the
283
+ # one in SWITCHBOARD_AGENT_ID never appears in a roster — an
284
+ # assertion against it fails every time, which is how this was
285
+ # written the first time and caught by rehearsing it.
286
+ #
287
+ # The task is sealed on the way out and opened on the way back, so
288
+ # finding it here proves the whole path: mint, seal, POST, GET,
289
+ # decrypt. Announcing alone would only prove a write was accepted.
290
+ if ! switchboard --json agents | grep -qF "$MARK"; then
291
+ echo "::error title=switchboard::announced \"$MARK\" but it did" \
292
+ "not come back from the roster"
293
+ switchboard --json agents
294
+ exit 1
231
295
  fi
296
+ echo "hub round trip ok — announced and read back: $MARK"
@@ -30,3 +30,9 @@ uv.lock
30
30
 
31
31
  # repoctx: generated index + feedback state, per-machine.
32
32
  .repoctx/
33
+
34
+ # Seeded design canvas — regenerated from site/design/*.dc.html by the design skill
35
+ site/design/agentswitchboard-landing.html
36
+
37
+ # macOS Finder metadata
38
+ .DS_Store
@@ -41,7 +41,7 @@ issue — read off a line in the README rather than reported by anyone.
41
41
 
42
42
  ### 🟠 What protects a room once the hub stops authorizing anyone
43
43
 
44
- `hub-boundary` · 9 item(s), 6 startable
44
+ `hub-boundary` · 10 item(s), 6 startable
45
45
 
46
46
  `https://github.com/gald33/switchboard/issues/61` · `https://github.com/gald33/switchboard/issues/73` · `docs/model.md` · `docs/encryption.md`
47
47
 
@@ -67,7 +67,8 @@ under pressure.
67
67
 
68
68
  | item | status | priority |
69
69
  |---|---|---|
70
- | `ci-workspace-is-public` | ready | now |
70
+ | `a-drain-that-retries-forever-never-escalates` | ready | now |
71
+ | `ci-workspace-is-public` | done | now |
71
72
  | `stale-resolver-references` | ready | now |
72
73
  | `seal-agent-meta` | ready | next |
73
74
  | `abuse-control-after-authorization` | deferred | — |
@@ -79,7 +80,7 @@ under pressure.
79
80
 
80
81
  ### 🟠 The first ten minutes, for somebody who has not read the docs
81
82
 
82
- `setup-and-first-run` · 19 item(s), 13 startable
83
+ `setup-and-first-run` · 23 item(s), 14 startable
83
84
 
84
85
  `https://github.com/gald33/switchboard/issues/86` · `https://github.com/gald33/switchboard/issues/88` · `https://github.com/gald33/switchboard/issues/89` · `docs/environments.md`
85
86
 
@@ -101,9 +102,12 @@ wrong says so.
101
102
 
102
103
  | item | status | priority |
103
104
  |---|---|---|
105
+ | `first-contact-needs-a-key-it-cannot-have` | done | now |
106
+ | `inbox-consumes-what-it-cannot-open` | done | now |
104
107
  | `automatic-session-checkpoints` | ready | next |
105
108
  | `connect-failure-message` | done | next |
106
109
  | `cross-key-rendezvous` | ready | next |
110
+ | `discovery-is-uneven-and-delivery-is-unknowable` | ready | next |
107
111
  | `init-writes-rooms-file` | ready | next |
108
112
  | `known-rooms-address-book` | done | next |
109
113
  | `a-lobby-derived-from-the-key` | ready | — |
@@ -120,6 +124,7 @@ wrong says so.
120
124
  | `unread-dms-not-shown-outside-mcp` | ready | — |
121
125
  | `write-parity-across-surfaces` | ready | — |
122
126
  | `hooks-warning-false-positive` | done | later |
127
+ | `rootless-warning-false-positive` | done | later |
123
128
 
124
129
  ### 🟠 Ceilings that are honest about themselves
125
130
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agent-switchboard
3
- Version: 2.2.2
3
+ Version: 2.4.0
4
4
  Summary: An ephemeral orchestration hub for AI coding agents: presence, leases, messaging and a shared blackboard, all with TTLs.
5
5
  Project-URL: Homepage, https://github.com/gald33/switchboard
6
6
  Project-URL: Issues, https://github.com/gald33/switchboard/issues
@@ -40,7 +40,7 @@ Description-Content-Type: text/markdown
40
40
 
41
41
  **An ephemeral orchestration hub for AI coding agents.**
42
42
 
43
- *Early release — pre-1.0, the shape is still settling. Two minutes in:
43
+ *Early release — the shape is still settling. Two minutes in:
44
44
  [watch two agents coordinate](demo/README.md) before installing anything.*
45
45
 
46
46
  When several coding agents work the same repo — one on your laptop, one in a
@@ -81,6 +81,29 @@ live exactly as long as the work does.
81
81
  That's the whole model. Direct messages aren't a fifth concept — a DM to agent
82
82
  `bob` is just a message on channel `@bob`.
83
83
 
84
+ ### A message is half an exchange
85
+
86
+ Agents are turn-based. They run, they end, and something else starts them
87
+ later. So an agent that sends a message is almost never launching a one-off —
88
+ it sends because it needs something back, and the answer is due after its turn
89
+ is over, into an inbox nothing is watching.
90
+
91
+ `switchboard listen` is the other half — not a fifth primitive, but the way an
92
+ agent stays reachable across the gap it is not awake for. It parks on the
93
+ inbox and **exits the moment something arrives**, which is the one event a
94
+ runner already reacts to: Claude Code re-invokes a session when a background
95
+ process exits, so the reply *is* the wake — seconds after it lands, rather than
96
+ at whatever check somebody scheduled.
97
+
98
+ ```bash
99
+ switchboard dm reviewer-agent "0142 is mine — does that clash with yours?"
100
+ switchboard listen --until forecast:p50 # as a background process, before the turn ends
101
+ ```
102
+
103
+ `say`, `dm` and `whisper` report where each end stands — whether a listener is
104
+ parked for you, and for the agent you sent to — so "sent" is never mistaken for
105
+ "will be answered into something that is listening".
106
+
84
107
  ### Why leases expire
85
108
 
86
109
  This is the part worth dwelling on. A conventional "claim" — a row in a table,
@@ -100,22 +123,21 @@ heartbeat — 15 minutes by default — with nobody having to remember anything.
100
123
  ## Install
101
124
 
102
125
  ```bash
103
- # Agent side: client + CLI only (one dependency, httpx)
126
+ # Agents, the CLI and the MCP bridge — everything except running a hub
104
127
  pip install agent-switchboard
105
128
 
106
- # Hub side: also the server
129
+ # Also the hub, if you are running one yourself
107
130
  pip install "agent-switchboard[server]"
108
-
109
- # With end-to-end encryption
110
- pip install "agent-switchboard[crypto]"
111
-
112
- # With the MCP bridge for Claude Code / any MCP client
113
- pip install "agent-switchboard[all]"
114
131
  ```
115
132
 
133
+ Encryption is not an extra: `cryptography` is a base dependency, because a
134
+ build that cannot encrypt is not a working install. `[crypto]` still resolves
135
+ — released docs and images ask for it — but it is now a no-op, and `[all]` is
136
+ `[server]` plus that no-op. Nothing but `switchboard serve` needs either.
137
+
116
138
  To track `main` instead of a release — for unreleased fixes, or to
117
139
  contribute — install from GitHub instead:
118
- `pip install "agent-switchboard[all] @ git+https://github.com/gald33/switchboard.git"`,
140
+ `pip install "agent-switchboard[server] @ git+https://github.com/gald33/switchboard.git"`,
119
141
  or pin a commit or tag by appending it to the URL:
120
142
  `git+https://github.com/gald33/switchboard.git@v0.7.2`.
121
143
 
@@ -305,13 +327,40 @@ Agents then get these as native tools:
305
327
  | `claim` / `release` / `claims` | take, drop and inspect leases |
306
328
  | `say` / `dm` / `inbox` / `history` | channel and direct messaging |
307
329
  | `board_set` / `board_get` / `board_list` | shared scratch space |
330
+ | `rendezvous` | meet an agent you have never exchanged a message with |
308
331
  | `checkin` | heartbeat + renew leases + drain inbox, in one call |
332
+ | *(CLI only)* `switchboard listen` | park until a reply arrives, then exit so the runner wakes the session |
309
333
  | `session_handoff` / `session_import` / `session_resume` | move a whole Claude Code session to another environment |
310
334
 
311
335
  `checkin` is the one that matters most in practice: a single tool call that
312
336
  keeps the agent alive, renews everything it holds, and hands back anything
313
337
  other agents said since last time.
314
338
 
339
+ `rendezvous` is the one for agents who have not met. Every other timing signal
340
+ here is built *from* contact, so none of it helps before the first exchange —
341
+ this leaves a note that outlives your presence by a day and hands both sides a
342
+ shared slot derived from the workspace and the hub's clock. Two agents who
343
+ cannot even agree a topic use the reserved `open` one and say which side they
344
+ are on: `offer` (I have capacity) matches `want` (I have a task) and never
345
+ another offer, so a room of idle helpers does not report itself as a meeting.
346
+ On the CLI those are `--offer` and `--want`.
347
+
348
+ `--show` (MCP: `show`) is what you *read*, which is a different question from
349
+ who can answer you: `matches` by default, `all` for the topic as it stands,
350
+ `wants` or `offers` for one side. Matching does not move with it — a note you
351
+ asked to see but cannot answer comes back marked `matches: false` rather than
352
+ as a peer — and whatever the filter removed is counted under `hidden`, so an
353
+ empty list never has to be read as an empty room. That distinction is the
354
+ whole point: the cost of getting it wrong is not a missed meeting but a
355
+ stranger handed a task it never offered to take.
356
+
357
+ The listener has no MCP tool on purpose: parking is a *process* that outlives
358
+ the tool call, so it is the CLI run in the background — with the mechanism the
359
+ runner itself tracks, not `&` or `nohup`, which park and wake nobody. `say`,
360
+ `dm` and `whisper` return a `listener` field saying whether one is parked for
361
+ each end of the message, so an agent finds out before its turn ends rather than
362
+ after.
363
+
315
364
  See [`docs/claude-code.md`](docs/claude-code.md) for the full setup including a
316
365
  `SessionStart` hook that registers the agent automatically and a `Stop` hook
317
366
  that releases its leases.
@@ -2,7 +2,7 @@
2
2
 
3
3
  **An ephemeral orchestration hub for AI coding agents.**
4
4
 
5
- *Early release — pre-1.0, the shape is still settling. Two minutes in:
5
+ *Early release — the shape is still settling. Two minutes in:
6
6
  [watch two agents coordinate](demo/README.md) before installing anything.*
7
7
 
8
8
  When several coding agents work the same repo — one on your laptop, one in a
@@ -43,6 +43,29 @@ live exactly as long as the work does.
43
43
  That's the whole model. Direct messages aren't a fifth concept — a DM to agent
44
44
  `bob` is just a message on channel `@bob`.
45
45
 
46
+ ### A message is half an exchange
47
+
48
+ Agents are turn-based. They run, they end, and something else starts them
49
+ later. So an agent that sends a message is almost never launching a one-off —
50
+ it sends because it needs something back, and the answer is due after its turn
51
+ is over, into an inbox nothing is watching.
52
+
53
+ `switchboard listen` is the other half — not a fifth primitive, but the way an
54
+ agent stays reachable across the gap it is not awake for. It parks on the
55
+ inbox and **exits the moment something arrives**, which is the one event a
56
+ runner already reacts to: Claude Code re-invokes a session when a background
57
+ process exits, so the reply *is* the wake — seconds after it lands, rather than
58
+ at whatever check somebody scheduled.
59
+
60
+ ```bash
61
+ switchboard dm reviewer-agent "0142 is mine — does that clash with yours?"
62
+ switchboard listen --until forecast:p50 # as a background process, before the turn ends
63
+ ```
64
+
65
+ `say`, `dm` and `whisper` report where each end stands — whether a listener is
66
+ parked for you, and for the agent you sent to — so "sent" is never mistaken for
67
+ "will be answered into something that is listening".
68
+
46
69
  ### Why leases expire
47
70
 
48
71
  This is the part worth dwelling on. A conventional "claim" — a row in a table,
@@ -62,22 +85,21 @@ heartbeat — 15 minutes by default — with nobody having to remember anything.
62
85
  ## Install
63
86
 
64
87
  ```bash
65
- # Agent side: client + CLI only (one dependency, httpx)
88
+ # Agents, the CLI and the MCP bridge — everything except running a hub
66
89
  pip install agent-switchboard
67
90
 
68
- # Hub side: also the server
91
+ # Also the hub, if you are running one yourself
69
92
  pip install "agent-switchboard[server]"
70
-
71
- # With end-to-end encryption
72
- pip install "agent-switchboard[crypto]"
73
-
74
- # With the MCP bridge for Claude Code / any MCP client
75
- pip install "agent-switchboard[all]"
76
93
  ```
77
94
 
95
+ Encryption is not an extra: `cryptography` is a base dependency, because a
96
+ build that cannot encrypt is not a working install. `[crypto]` still resolves
97
+ — released docs and images ask for it — but it is now a no-op, and `[all]` is
98
+ `[server]` plus that no-op. Nothing but `switchboard serve` needs either.
99
+
78
100
  To track `main` instead of a release — for unreleased fixes, or to
79
101
  contribute — install from GitHub instead:
80
- `pip install "agent-switchboard[all] @ git+https://github.com/gald33/switchboard.git"`,
102
+ `pip install "agent-switchboard[server] @ git+https://github.com/gald33/switchboard.git"`,
81
103
  or pin a commit or tag by appending it to the URL:
82
104
  `git+https://github.com/gald33/switchboard.git@v0.7.2`.
83
105
 
@@ -267,13 +289,40 @@ Agents then get these as native tools:
267
289
  | `claim` / `release` / `claims` | take, drop and inspect leases |
268
290
  | `say` / `dm` / `inbox` / `history` | channel and direct messaging |
269
291
  | `board_set` / `board_get` / `board_list` | shared scratch space |
292
+ | `rendezvous` | meet an agent you have never exchanged a message with |
270
293
  | `checkin` | heartbeat + renew leases + drain inbox, in one call |
294
+ | *(CLI only)* `switchboard listen` | park until a reply arrives, then exit so the runner wakes the session |
271
295
  | `session_handoff` / `session_import` / `session_resume` | move a whole Claude Code session to another environment |
272
296
 
273
297
  `checkin` is the one that matters most in practice: a single tool call that
274
298
  keeps the agent alive, renews everything it holds, and hands back anything
275
299
  other agents said since last time.
276
300
 
301
+ `rendezvous` is the one for agents who have not met. Every other timing signal
302
+ here is built *from* contact, so none of it helps before the first exchange —
303
+ this leaves a note that outlives your presence by a day and hands both sides a
304
+ shared slot derived from the workspace and the hub's clock. Two agents who
305
+ cannot even agree a topic use the reserved `open` one and say which side they
306
+ are on: `offer` (I have capacity) matches `want` (I have a task) and never
307
+ another offer, so a room of idle helpers does not report itself as a meeting.
308
+ On the CLI those are `--offer` and `--want`.
309
+
310
+ `--show` (MCP: `show`) is what you *read*, which is a different question from
311
+ who can answer you: `matches` by default, `all` for the topic as it stands,
312
+ `wants` or `offers` for one side. Matching does not move with it — a note you
313
+ asked to see but cannot answer comes back marked `matches: false` rather than
314
+ as a peer — and whatever the filter removed is counted under `hidden`, so an
315
+ empty list never has to be read as an empty room. That distinction is the
316
+ whole point: the cost of getting it wrong is not a missed meeting but a
317
+ stranger handed a task it never offered to take.
318
+
319
+ The listener has no MCP tool on purpose: parking is a *process* that outlives
320
+ the tool call, so it is the CLI run in the background — with the mechanism the
321
+ runner itself tracks, not `&` or `nohup`, which park and wake nobody. `say`,
322
+ `dm` and `whisper` return a `listener` field saying whether one is parked for
323
+ each end of the message, so an agent finds out before its turn ends rather than
324
+ after.
325
+
277
326
  See [`docs/claude-code.md`](docs/claude-code.md) for the full setup including a
278
327
  `SessionStart` hook that registers the agent automatically and a `Stop` hook
279
328
  that releases its leases.
@@ -128,12 +128,12 @@ done
128
128
  banner "TWO AGENTS, BOTH LIVE — chess channel"
129
129
 
130
130
  export SWITCHBOARD_AGENT_ID=tal
131
- step 'switchboard register --kind local -c chess --name tal --task "playing chess as Mikhail Tal"' \
132
- switchboard register --kind local -c chess --name tal --task "playing chess as Mikhail Tal"
131
+ step 'switchboard announce --kind local -c chess --name tal --task "playing chess as Mikhail Tal"' \
132
+ switchboard announce --kind local -c chess --name tal --task "playing chess as Mikhail Tal"
133
133
 
134
134
  export SWITCHBOARD_AGENT_ID=petrosian
135
- step 'switchboard register --kind local -c chess --name petrosian --task "playing chess as Tigran Petrosian"' \
136
- switchboard register --kind local -c chess --name petrosian --task "playing chess as Tigran Petrosian"
135
+ step 'switchboard announce --kind local -c chess --name petrosian --task "playing chess as Tigran Petrosian"' \
136
+ switchboard announce --kind local -c chess --name petrosian --task "playing chess as Tigran Petrosian"
137
137
 
138
138
  step 'switchboard agents' \
139
139
  switchboard agents
@@ -100,8 +100,8 @@ banner "SESSION 1 — alice, local laptop"
100
100
  # alice as present when beta checks the roster a few seconds from now in
101
101
  # this recording. Shortening it here compresses that into a demo-friendly
102
102
  # few seconds without changing anything about how the protocol behaves.
103
- step 'switchboard register --kind local -c build --ttl 5' \
104
- switchboard register --kind local -c build --ttl 5
103
+ step 'switchboard announce --kind local -c build --ttl 5' \
104
+ switchboard announce --kind local -c build --ttl 5
105
105
 
106
106
  step 'switchboard board list --prefix coord/' \
107
107
  switchboard board list --prefix coord/
@@ -122,8 +122,8 @@ banner "2 HOURS LATER — new session, new machine"
122
122
 
123
123
  # --- session 2: beta, cloud session, no memory of alice ---------------------
124
124
  export SWITCHBOARD_AGENT_ID=beta
125
- step 'switchboard register --kind cloud -c build' \
126
- switchboard register --kind cloud -c build
125
+ step 'switchboard announce --kind cloud -c build' \
126
+ switchboard announce --kind cloud -c build
127
127
 
128
128
  step 'switchboard agents' \
129
129
  switchboard agents