Skip to content

Run per-session sidecars on a per-session network#13

Merged
CrypticSwarm merged 3 commits into
masterfrom
tongs-phase-7c-session-networks
Jun 18, 2026
Merged

Run per-session sidecars on a per-session network#13
CrypticSwarm merged 3 commits into
masterfrom
tongs-phase-7c-session-networks

Conversation

@CrypticSwarm

Copy link
Copy Markdown
Owner

Summary

Teaches the host launcher (scripts/run_anvil.py) to start per-session sidecar
containers, each on a docker network scoped to a single harness session. Until
now the launcher started only long-lived (shared) sidecars on the harness's
existing network; this adds the per-session lifecycle and the network isolation
it needs.

What this does

When a discovered sidecar declares a per-session lifecycle, the launcher now:

  • creates a docker network named for the harness container's --name, so
    concurrent harness sessions cannot reach each other's sidecars by container
    name;
  • starts each per-session sidecar on that network under its canonical
    --network-alias, so the name the agent dials is identical across worktrees
    (never the session-suffixed container name);
  • connects each network-facing shared sidecar to the session network for the
    duration of the session, and disconnects -- but does not stop -- it on exit;
  • joins the harness to the session network plus the pre-existing NETWORK=
    network.

Because docker run attaches only one network at creation, a harness that joins
both networks is created, connected to the extra network, then started attached
(docker create -> docker network connect -> docker start --attach). A new
pure tongs.to_create_argv rewrites only the run subcommand to create,
preserving every other token, so the create path reuses the exact argv the
Makefile built.

On exit -- including Ctrl-C -- the per-session sidecars and the per-session
network are torn down (and the connected shared sidecars disconnected) while
the long-lived shared sidecars keep running. The per-session connect is made
idempotent with a best-effort disconnect first, so a network left behind by a
hard-killed prior session does not wedge the next launch.

Structure

The per-session network calls (create / connect / disconnect / remove) and the
create -> connect -> start harness run go through the existing DockerCLI seam,
so the whole sequence is unit-tested against an in-process fake: network
create/teardown, per-session sidecar start under its alias, shared-sidecar
connect/disconnect, readiness probing on the session network, Ctrl-C teardown,
the missing---name guard, and the byte-identical passthrough exec.

A container that must join more than one network has to be created,
connected to the extra networks, then started -- docker run only attaches
one network at creation. Add a pure argv builder that swaps just the run
subcommand for create, preserving every other token, so the multi-network
launch path can reuse the anvil argv the Makefile already built.
Session tongs live on a per-session network so concurrent anvils cannot
reach each other's sidecars by container name. Add the DockerCLI methods
that path needs: ensure_network (inspect-or-create, reusing a leftover from
a crashed session), network_connect (attach a shared tong under its
canonical alias), and best-effort network_disconnect/network_rm for
teardown.

An anvil that joins both its per-session network and the pre-existing
NETWORK= network cannot be started with a single docker run, so add
run_foreground_multi: create the anvil on its primary network, connect the
extra networks, then start it attached. Teardown owns removing the created
container, so a failed connect/start does not orphan it.
A `session` tong is per-session: when one is discovered the launcher
creates a network named for the anvil's --name handle, starts the session
tongs on it under their canonical aliases, connects each network-facing
shared tong to it for this session, and joins the anvil to it plus the
pre-existing NETWORK= network (via create -> connect -> start, since
docker run attaches only one network). Readiness is probed on the network
the anvil will use, so a shared tong is checked at the alias the anvil
dials.

The per-session connect of a shared tong is made idempotent with a
best-effort disconnect first: a hard-killed prior session can leave its
network behind with the shared tong still attached, and ensure_network
reuses that network, so a stale endpoint must not fail the connect.

On exit -- including SIGINT -- the session tongs and the per-session
network are torn down and the connected shared tongs disconnected, while
the long-lived shared tongs keep running. Removing the session tongs and
the anvil before the network avoids docker's refusal to delete a network
with live endpoints.

The secret, MCP, and volume guards stay: only the bare session-lifecycle
refusal is lifted, so a session tong that needs secret delivery or MCP
config is still refused rather than started half-wired.
@CrypticSwarm CrypticSwarm merged commit 3d68429 into master Jun 18, 2026
1 check passed
@CrypticSwarm CrypticSwarm deleted the tongs-phase-7c-session-networks branch June 18, 2026 04:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant