Skip to content

Commit 3a2276d

Browse files
author
deva
committed
feat(bridge): vendor smux tmux-bridge as layer-2 agent comms
- scripts/tmux-bridge: byte-identical copy from smux commit 95bf0b6 (github.com/ShawnPana/smux, MIT). 403-line bash CLI for cross-pane comms: list, read, type, keys, message, name, resolve, doctor. - Read-before-act guard via /tmp/tmux-bridge-read-<pane_id> sentinel prevents agents from blindly writing to panes they have not inspected. - Installed at /usr/local/bin/tmux-bridge in container images, sits alongside existing deva-bridge-tmux (layer 1 socat TCP tunnel). - Provenance pinned in scripts/tmux-bridge.VENDORED (upstream commit + SHA256 ed66862b...); upstream MIT license shipped in scripts/THIRD_PARTY_LICENSES/smux-LICENSE. - docs/tmux-bridge-agent-comms.md explains two-layer composition, security model, socket detection order, and read-guard semantics. - CI smoke step builds an ephemeral tmux server inside the image and exercises the full CLI surface (list/name/resolve/read/type) plus a negative assertion on the read-guard. - Zero touches to deva.sh, auth, or docker-entrypoint.sh; purely additive layer-2 adoption.
1 parent 09ca3b0 commit 3a2276d

8 files changed

Lines changed: 600 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,44 @@ jobs:
147147
deva-smoke:ci \
148148
bash -lc 'link="/tmp/claude-mcp-browser-bridge-$(id -un)"; test -L "$link"; test "$(readlink "$link")" = "/deva-host-chrome-bridge"'
149149
150+
- name: Smoke tmux-bridge CLI surface
151+
shell: bash
152+
run: |
153+
set -euo pipefail
154+
# tmux-bridge is the layer-2 agent comms CLI vendored from smux.
155+
# We assert it's installed, executable, runs outside a tmux pane for
156+
# the version/help/id error paths, and that tmux itself is present
157+
# so a future operator can drive tmux-bridge against host tmux.
158+
docker run --rm deva-smoke:ci bash -lc '
159+
set -euo pipefail
160+
command -v tmux-bridge
161+
command -v tmux
162+
tmux-bridge version
163+
tmux-bridge --help | grep -q "cross-pane communication"
164+
# id requires $TMUX_PANE; outside tmux it must error cleanly.
165+
if tmux-bridge id 2>/dev/null; then
166+
echo "tmux-bridge id should fail outside a tmux pane" >&2
167+
exit 1
168+
fi
169+
# Ephemeral tmux server to prove list/name/read/type work end-to-end.
170+
sock="/tmp/tmux-smoke.sock"
171+
tmux -S "$sock" new-session -d -s smoke "sleep 30"
172+
export TMUX_BRIDGE_SOCKET="$sock"
173+
tmux-bridge list | tee /tmp/list.out
174+
grep -q "smoke:0" /tmp/list.out
175+
target="$(tmux -S "$sock" display-message -p "#{pane_id}")"
176+
tmux-bridge name "$target" smoke-worker
177+
tmux-bridge resolve smoke-worker
178+
tmux-bridge read "$target" 5 >/dev/null
179+
# read-guard: must read before type; second type without read must fail
180+
tmux-bridge type smoke-worker "echo hi"
181+
if tmux-bridge type smoke-worker "echo twice" 2>/dev/null; then
182+
echo "read-guard should have blocked second type without read" >&2
183+
exit 1
184+
fi
185+
tmux -S "$sock" kill-server
186+
'
187+
150188
docs:
151189
name: Docs Build
152190
runs-on: ubuntu-latest

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ All notable changes to deva.sh will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
10+
### Added
11+
- `scripts/tmux-bridge` vendored from upstream smux (commit 95bf0b6, MIT) for layer-2 agent-to-agent communication over tmux panes: read/type/keys/label/envelope/doctor
12+
- `tmux-bridge` installed at `/usr/local/bin/tmux-bridge` in container images; composes with existing `deva-bridge-tmux` (layer 1, kernel boundary)
13+
- `scripts/THIRD_PARTY_LICENSES/smux-LICENSE` and `scripts/tmux-bridge.VENDORED` provenance metadata pinning upstream commit + SHA256
14+
- `docs/tmux-bridge-agent-comms.md` explaining the two-layer bridge composition, read-before-act guard, and socket detection order
15+
- CI smoke test exercising the full `tmux-bridge` CLI surface (list/name/resolve/read/type/read-guard) against an ephemeral tmux server inside the built image
16+
817
## [0.10.0] - 2026-03-24
918

1019
### Added

DEV-LOGS.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,17 @@
1313
- Minimal markdown markers, no unnecessary formatting, minimal emojis.
1414
- Reference issue numbers in the format `#<issue-number>` for easy linking.
1515

16+
# [2026-04-13] Dev Log: adopt smux tmux-bridge as layer-2 agent comms
17+
- Why: deva-v2 proposal left the agent-to-agent transport CLI as an open question; smux (github.com/ShawnPana/smux) shipped exactly the shape we sketched (read/type/keys/label/envelope) in 403 lines of bash, MIT-licensed. Reinventing it would be waste. The existing `deva-bridge-tmux` (socat TCP) is layer 1 (kernel boundary); `tmux-bridge` is layer 2 (semantic). They compose cleanly.
18+
- What:
19+
- vendored `scripts/tmux-bridge` byte-for-byte from upstream commit `95bf0b6` (SHA256 `ed66862b...`), not downloaded at build time, so image builds stay reproducible and auditable
20+
- recorded provenance in `scripts/tmux-bridge.VENDORED` and shipped the upstream MIT license at `scripts/THIRD_PARTY_LICENSES/smux-LICENSE`
21+
- installed `tmux-bridge` into container images at `/usr/local/bin/tmux-bridge` alongside existing `deva-bridge-tmux` (Dockerfile COPY + chmod)
22+
- wrote `docs/tmux-bridge-agent-comms.md` covering the two-layer composition, security model, socket detection order, and the read-before-act guard (sentinel at `/tmp/tmux-bridge-read-<pane_id>`, cleared on any write — main safety net against an agent hallucinating into the wrong pane)
23+
- added CI smoke step that builds an ephemeral tmux server inside the image and exercises the full CLI surface: `list`, `name`, `resolve`, `read`, `type`, plus a negative assertion that the read-guard blocks a second `type` without an intervening `read`
24+
- did not touch `deva.sh`, auth wiring, or `docker-entrypoint.sh` — layer 2 is purely additive
25+
- Result: agents inside deva containers can now drive each other's tmux panes with a single 403-line CLI that was not ours to write. Layer 1 (our own socat tunnel) and layer 2 (vendored smux) compose: once `deva-bridge-tmux` is running, setting `TMUX_BRIDGE_SOCKET=/tmp/host-tmux.sock` (or just attaching to tmux via `-S`) lets `tmux-bridge` target panes on the HOST tmux server from inside the container. Layer 3 (coordinator/router with text envelopes, state detection, scratchpad) remains an open design question tracked in `docs/devlog/260401-deva-v2-proposal.org`; this PR intentionally does not touch it.
26+
1627
# [2026-03-11] Dev Log: deva.sh docs spine for OSS release
1728
- Why: the repo had a decent landing page but still dumped too much context into one README and did not read like an organized OSS project
1829
- What:

Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,9 +237,13 @@ USER root
237237

238238
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
239239
COPY scripts/deva-bridge-tmux /usr/local/bin/deva-bridge-tmux
240+
# tmux-bridge: vendored from smux (layer-2 agent comms CLI over tmux panes)
241+
# See scripts/tmux-bridge.VENDORED for upstream commit and SHA256 pin.
242+
COPY scripts/tmux-bridge /usr/local/bin/tmux-bridge
240243

241244
RUN chmod 755 /usr/local/bin/docker-entrypoint.sh && \
242245
chmod 755 /usr/local/bin/deva-bridge-tmux && \
246+
chmod 755 /usr/local/bin/tmux-bridge && \
243247
chmod -R 755 /usr/local/bin/scripts || true
244248

245249
WORKDIR /root

docs/tmux-bridge-agent-comms.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# tmux-bridge: agent-to-agent comms in deva containers
2+
3+
deva ships two tmux bridge layers. They compose.
4+
5+
Layer 1 deva-bridge-tmux kernel boundary
6+
(scripts/deva-bridge-tmux) container tmux client -> host tmux server
7+
socat TCP tunnel via host.docker.internal:41555
8+
9+
Layer 2 tmux-bridge semantic CLI
10+
(scripts/tmux-bridge) read/type/keys/label/envelope
11+
vendored from smux for agents to drive each other's panes
12+
13+
Layer 1 is the plumbing that lets the container see host tmux at all. Layer 2
14+
is what agents actually call.
15+
16+
## Security
17+
18+
Both layers are privileged host bridges. If you run them, the container can
19+
execute arbitrary commands on the host tmux server (send-keys, run-shell,
20+
scrollback). This is deliberate for trusted dev workflows. Do not enable on
21+
untrusted code.
22+
23+
## Quick start
24+
25+
Host (macOS):
26+
27+
deva-bridge-tmux-host # expose host tmux over TCP:41555
28+
29+
Container (inside a deva agent):
30+
31+
deva-bridge-tmux # start socat; creates /tmp/host-tmux.sock
32+
tmux -S /tmp/host-tmux.sock attach # optional: attach to host session
33+
34+
From another pane (or the same container, any agent CLI that can shell out):
35+
36+
tmux-bridge list # see all panes
37+
tmux-bridge name %1 planner # label a pane
38+
tmux-bridge read planner 50 # read last 50 lines
39+
tmux-bridge message planner "found 3 issues in auth.py"
40+
tmux-bridge type planner "rerun tests"
41+
tmux-bridge keys planner Enter
42+
43+
## Socket detection
44+
45+
`tmux-bridge` auto-detects the tmux server socket in this order:
46+
47+
1. `$TMUX_BRIDGE_SOCKET` env var (explicit override)
48+
2. `$TMUX` (set automatically when you are inside a tmux pane)
49+
3. Scan `/tmp/tmux-<uid>/*` for a server that owns `$TMUX_PANE`
50+
4. Default tmux server
51+
52+
For deva containers talking to host tmux via the layer-1 bridge, attach to
53+
tmux first (step 2 fires) or set the override:
54+
55+
export TMUX_BRIDGE_SOCKET=/tmp/host-tmux.sock
56+
57+
## Read-before-act guard
58+
59+
`tmux-bridge` enforces that agents `read` a pane before they can `type`,
60+
`message`, or `keys` into it. This is the main safety net against "agent
61+
blindly hallucinates into the wrong pane."
62+
63+
The guard is a sentinel at `/tmp/tmux-bridge-read-<pane_id>`. Reading sets
64+
it; any write clears it. So the contract is:
65+
66+
1. `tmux-bridge read <target>` — look at the pane's current state
67+
2. `tmux-bridge type <target> "..."` — act on what you saw
68+
3. To act again, read again.
69+
70+
## Diagnostics
71+
72+
tmux-bridge doctor
73+
74+
Prints env vars, detected socket, visible panes, and a pass/fail summary.
75+
Run this first when things go wrong.
76+
77+
## Provenance
78+
79+
`scripts/tmux-bridge` is vendored byte-for-byte from upstream smux
80+
(github.com/ShawnPana/smux). See `scripts/tmux-bridge.VENDORED` for the
81+
pinned commit and SHA256. License is MIT, reproduced in
82+
`scripts/THIRD_PARTY_LICENSES/smux-LICENSE`.
83+
84+
`scripts/deva-bridge-tmux` and `scripts/deva-bridge-tmux-host` are deva's
85+
own work (see `docs/devlog/20260108-deva-bridge-tmux.org`).
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 shawn pana
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.

0 commit comments

Comments
 (0)