Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,44 @@ jobs:
deva-smoke:ci \
bash -lc 'link="/tmp/claude-mcp-browser-bridge-$(id -un)"; test -L "$link"; test "$(readlink "$link")" = "/deva-host-chrome-bridge"'

- name: Smoke tmux-bridge CLI surface
shell: bash
run: |
set -euo pipefail
# tmux-bridge is the layer-2 agent comms CLI vendored from smux.
# We assert it's installed, executable, runs outside a tmux pane for
# the version/help/id error paths, and that tmux itself is present
# so a future operator can drive tmux-bridge against host tmux.
docker run --rm deva-smoke:ci bash -lc '
set -euo pipefail
command -v tmux-bridge
command -v tmux
tmux-bridge version
tmux-bridge --help | grep -q "cross-pane communication"
# id requires $TMUX_PANE; outside tmux it must error cleanly.
if tmux-bridge id 2>/dev/null; then
echo "tmux-bridge id should fail outside a tmux pane" >&2
exit 1
fi
# Ephemeral tmux server to prove list/name/read/type work end-to-end.
sock="/tmp/tmux-smoke.sock"
tmux -S "$sock" new-session -d -s smoke "sleep 30"
export TMUX_BRIDGE_SOCKET="$sock"
tmux-bridge list | tee /tmp/list.out
grep -q "smoke:0" /tmp/list.out
target="$(tmux -S "$sock" display-message -p "#{pane_id}")"
tmux-bridge name "$target" smoke-worker
tmux-bridge resolve smoke-worker
tmux-bridge read "$target" 5 >/dev/null
# read-guard: must read before type; second type without read must fail
tmux-bridge type smoke-worker "echo hi"
if tmux-bridge type smoke-worker "echo twice" 2>/dev/null; then
echo "read-guard should have blocked second type without read" >&2
exit 1
fi
tmux -S "$sock" kill-server
'

docs:
name: Docs Build
runs-on: ubuntu-latest
Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,15 @@ All notable changes to deva.sh will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added
- `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
- `tmux-bridge` installed at `/usr/local/bin/tmux-bridge` in container images; composes with existing `deva-bridge-tmux` (layer 1, kernel boundary)
- `scripts/THIRD_PARTY_LICENSES/smux-LICENSE` and `scripts/tmux-bridge.VENDORED` provenance metadata pinning upstream commit + SHA256
- `docs/tmux-bridge-agent-comms.md` explaining the two-layer bridge composition, read-before-act guard, and socket detection order
- 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

## [0.10.0] - 2026-03-24

### Added
Expand Down
11 changes: 11 additions & 0 deletions DEV-LOGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@
- Minimal markdown markers, no unnecessary formatting, minimal emojis.
- Reference issue numbers in the format `#<issue-number>` for easy linking.

# [2026-04-13] Dev Log: adopt smux tmux-bridge as layer-2 agent comms
- 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.
- What:
- 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
- recorded provenance in `scripts/tmux-bridge.VENDORED` and shipped the upstream MIT license at `scripts/THIRD_PARTY_LICENSES/smux-LICENSE`
- installed `tmux-bridge` into container images at `/usr/local/bin/tmux-bridge` alongside existing `deva-bridge-tmux` (Dockerfile COPY + chmod)
- 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)
- 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`
- did not touch `deva.sh`, auth wiring, or `docker-entrypoint.sh` — layer 2 is purely additive
- 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.

# [2026-03-11] Dev Log: deva.sh docs spine for OSS release
- 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
- What:
Expand Down
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,13 @@ USER root

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

RUN chmod 755 /usr/local/bin/docker-entrypoint.sh && \
chmod 755 /usr/local/bin/deva-bridge-tmux && \
chmod 755 /usr/local/bin/tmux-bridge && \
chmod -R 755 /usr/local/bin/scripts || true

WORKDIR /root
Expand Down
85 changes: 85 additions & 0 deletions docs/tmux-bridge-agent-comms.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# tmux-bridge: agent-to-agent comms in deva containers

deva ships two tmux bridge layers. They compose.

Layer 1 deva-bridge-tmux kernel boundary
(scripts/deva-bridge-tmux) container tmux client -> host tmux server
socat TCP tunnel via host.docker.internal:41555

Layer 2 tmux-bridge semantic CLI
(scripts/tmux-bridge) read/type/keys/label/envelope
vendored from smux for agents to drive each other's panes

Layer 1 is the plumbing that lets the container see host tmux at all. Layer 2
is what agents actually call.

## Security

Both layers are privileged host bridges. If you run them, the container can
execute arbitrary commands on the host tmux server (send-keys, run-shell,
scrollback). This is deliberate for trusted dev workflows. Do not enable on
untrusted code.

## Quick start

Host (macOS):

deva-bridge-tmux-host # expose host tmux over TCP:41555

Container (inside a deva agent):

deva-bridge-tmux # start socat; creates /tmp/host-tmux.sock
tmux -S /tmp/host-tmux.sock attach # optional: attach to host session

From another pane (or the same container, any agent CLI that can shell out):

tmux-bridge list # see all panes
tmux-bridge name %1 planner # label a pane
tmux-bridge read planner 50 # read last 50 lines
tmux-bridge message planner "found 3 issues in auth.py"
tmux-bridge type planner "rerun tests"
tmux-bridge keys planner Enter

## Socket detection

`tmux-bridge` auto-detects the tmux server socket in this order:

1. `$TMUX_BRIDGE_SOCKET` env var (explicit override)
2. `$TMUX` (set automatically when you are inside a tmux pane)
3. Scan `/tmp/tmux-<uid>/*` for a server that owns `$TMUX_PANE`
4. Default tmux server

For deva containers talking to host tmux via the layer-1 bridge, attach to
tmux first (step 2 fires) or set the override:

export TMUX_BRIDGE_SOCKET=/tmp/host-tmux.sock

## Read-before-act guard

`tmux-bridge` enforces that agents `read` a pane before they can `type`,
`message`, or `keys` into it. This is the main safety net against "agent
blindly hallucinates into the wrong pane."

The guard is a sentinel at `/tmp/tmux-bridge-read-<pane_id>`. Reading sets
it; any write clears it. So the contract is:

1. `tmux-bridge read <target>` — look at the pane's current state
2. `tmux-bridge type <target> "..."` — act on what you saw
3. To act again, read again.

## Diagnostics

tmux-bridge doctor

Prints env vars, detected socket, visible panes, and a pass/fail summary.
Run this first when things go wrong.

## Provenance

`scripts/tmux-bridge` is vendored byte-for-byte from upstream smux
(github.com/ShawnPana/smux). See `scripts/tmux-bridge.VENDORED` for the
pinned commit and SHA256. License is MIT, reproduced in
`scripts/THIRD_PARTY_LICENSES/smux-LICENSE`.

`scripts/deva-bridge-tmux` and `scripts/deva-bridge-tmux-host` are deva's
own work (see `docs/devlog/20260108-deva-bridge-tmux.org`).
21 changes: 21 additions & 0 deletions scripts/THIRD_PARTY_LICENSES/smux-LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 shawn pana

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Loading
Loading