You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Make session shell isolation pluggable (just-bash default, Docker container opt-in)
- Add SessionEnvironment interface (environments/types.ts) implemented by
justBashEnvironment.ts (default, reuses bash.ts unmodified) and
containerEnvironment.ts (opt-in, per-session Docker container).
- Select the strategy via a single line in environments/index.ts, with the
alternative commented out alongside its import.
- Restore container-mode support files from the prior containerize-tools
branch: containerFs.ts, docker/image.ts, docker/sessionContainer.ts,
session-image/Dockerfile.
- Make chatSocket.ts isolation-agnostic: bang-commands and disposal now go
through session.environment; track active environments so they are
disposed of when sessions end or fail to start.
- Add getSessionDir() to the storage provider interface (disk implementation
returns a real path; in-memory throws, since container mode needs a real
host directory to bind-mount).
- Add commented-out docker.sock mount and HOST_SESSIONS_DIR to
docker-compose.yml for running the app itself in compose with container
mode enabled.
- Document the switch in README.md.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy file name to clipboardExpand all lines: README.md
+23-4Lines changed: 23 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -35,6 +35,25 @@ To use a purely in-memory virtual filesystem instead, set an environment variabl
35
35
36
36
In realistic server deployments it would be better to use disk rather than in-memory storage, because disk space is more cheaply available. But if you're building a client-side application that creates large numbers of short-lived agent sessions, it might work well to use an in-memory VFS.
37
37
38
+
### Switching to container-based isolation
39
+
40
+
By default, each session's shell tool is powered by [just-bash](https://github.com/aspect-build/just-bash), an in-process virtual filesystem and shell simulator. This is the simplest option: it needs no extra setup at all.
41
+
42
+
As an alternative, this sample also includes a container-based isolation strategy: each session gets its own small, disposable Linux container (built from `app/session-image/Dockerfile`), and the `bash` tool runs commands for real inside it. The session's directory on disk is bind-mounted read-write into the container, so file tools and the `bash` tool both operate on the same files.
43
+
44
+
Both strategies implement the same `SessionEnvironment` interface (see `app/src/api/environments/types.ts`), so switching between them is a one-line change in `app/src/api/environments/index.ts`:
To switch, comment out the first line and uncomment the second. This requires:
52
+
53
+
- Docker installed and running on the machine that runs the app server.
54
+
- Disk-backed session storage (the default) rather than the in-memory VFS mode above, since containers need a real host directory to bind-mount.
55
+
- If you're also running the app server itself via `docker-compose` (rather than `npm run dev` directly on the host), uncomment the Docker socket bind mount and `HOST_SESSIONS_DIR` lines in `docker-compose.yml`, so the app can talk to the host's Docker daemon to start sibling containers with correctly-resolved bind mount paths.
56
+
38
57
## Architecture
39
58
40
59
```mermaid
@@ -52,9 +71,8 @@ When a user connects, the app server creates an isolated session with:
52
71
53
72
- A **Copilot SDK session** (`CopilotSession`) that maintains conversation state, tool handlers, and event streaming.
54
73
- We limit it to using tools that are intended to be safe in multi-user environments because they don't read/write files.
55
-
- The session's only tool that can operate on disk is `bash`, but this is swapped out for a virtual version (see below).
56
-
- A **virtual filesystem** (in-memory or disk-backed) scoped to that session. The Copilot agent reads and writes files within this filesystem only. It cannot see the server's disk or the state of other sessions.
57
-
- A **virtual bash runtime** ([just-bash](https://github.com/aspect-build/just-bash)) attached to the virtual filesystem, exposed to the agent as a tool. Network access is restricted to a small allowlist.
74
+
- The session's only tool that can operate on disk is `bash`, but this is swapped out for an isolated version (see below).
75
+
- A **session environment** (see `app/src/api/environments/`) providing an isolated filesystem and a `bash` tool. Two implementations are included - the default uses [just-bash](https://github.com/aspect-build/just-bash), an in-process virtual filesystem and shell simulator; an alternative runs each session in its own small, disposable Linux container instead. See [Switching to container-based isolation](#switching-to-container-based-isolation).
58
76
59
77
Multiple browser tabs can observe the same session simultaneously — the server maintains a single `CopilotSession` per session ID and fans out events to all connected WebSockets. To see this, copy and paste your session URL into a second browser window or tab.
60
78
@@ -76,7 +94,8 @@ The `rsync-filestore` container is a minimal Alpine image running an rsync daemo
76
94
*`api`: server-side code that defines and manages agent sessions
77
95
*`chatSocket.ts`: starts a WebSocket listener. As clients connect/disconnect, starts and stops `CopilotSession` instances and synchronizes storage to `rsync-filestore`
78
96
*`storage/`: simple VFS implementations
79
-
*`bash.ts`: swaps out Copilot SDK's built-in shell tool with one backed by [just-bash](https://github.com/vercel-labs/just-bash). This is simply an example - you could instead map it into a per-session container, any other isolated shell. Various other open source projects provide isolated shells.
97
+
*`environments/`: pluggable session isolation strategies (see [Switching to container-based isolation](#switching-to-container-based-isolation)). `justBashEnvironment.ts` is the default; `containerEnvironment.ts` is the container-based alternative. Both implement the same `SessionEnvironment` interface (`types.ts`), selected by a single line in `index.ts`.
98
+
*`bash.ts`: swaps out Copilot SDK's built-in shell tool with one backed by [just-bash](https://github.com/vercel-labs/just-bash), used by the default `justBashEnvironment`.
80
99
*`web-ui`: an Express+React application providing the user interface
81
100
*`hooks/useChat.ts`: opens the websocket connection to `api/chat` and uses a reducer pattern to convert the event stream into a UI
82
101
* everything else: generic chat UI (a lot of code but nothing interesting)
0 commit comments