Container Conduit
Install this skill

Paste this into Claude Code (VS Code panel, Adom editor, or terminal) to install:

Search the Adom Wiki for the skill "Container Conduit" (slug: container-conduit) at https://wiki-ufypy5dpx93o.adom.cloud/wiki/skills/container-conduit and install it into my local ~/.claude/skills/container-conduit/ directory. Fetch the skill_source content from the wiki page and save it as SKILL.md. Then confirm it's installed by showing the first 5 lines.
?
What is a skill? Skills are instructions that teach AI assistants like Claude Code how to perform specific tasks. The description below is loaded into the AI as context when you invoke this skill. Well-written skills make the AI significantly more effective. Like Wikipedia, anyone can improve a skill by clicking Edit AI Skill — or have your AI submit an edit on your behalf.

Screenshots

Description

Edit AI Skill

Container Conduit

Container Conduit is a WebSocket bridge that connects a main Gallia container to one or more satellite Adom containers. It gives Claude Code full remote control over satellite containers — execute commands, transfer files, monitor system health, and open persistent interactive shell sessions — all without leaving your main workspace.

The Gallia Viewer dashboard provides a browser-based interactive terminal (xterm.js) with full TTY support for curses applications like vim, nano, and htop.


Architecture

Main Container (Gallia)                  Satellite Container(s)
  server.js (WS port 8800)  ←──WS──→  agent.js
  HTTP API  (port 8801)                   ↑
       ↑                              install.sh (bootstrap)
  MCP tools (mcp/server.js)
       ↑
  Claude Code / Dashboard
ComponentRole
server.jsWebSocket server (port 8800) + HTTP API (port 8801) — accepts agent connections, relays commands, serves the dashboard
agent.jsLightweight satellite agent — handles exec, file ops, system status, and PTY sessions
mcp/server.jsMCP stdio server — exposes all Container Conduit tools to Claude Code
dashboard.htmlInteractive management dashboard in Gallia Viewer with Shell, Terminal, and Prompts tabs

MCP Tools

All tools are prefixed container_ and available to Claude Code via MCP:

Command Execution

ToolDescription
container_execExecute a shell command on a specific container (one-shot)
container_exec_allExecute a command on all connected containers simultaneously

Persistent Shell Sessions

ToolDescription
container_shell_startStart a persistent interactive shell session (returns sessionId)
container_shell_execRun a command in a persistent shell — state persists across calls (cwd, env vars, aliases)
container_shell_stopStop a persistent shell session

File Operations

ToolDescription
container_file_readRead a file from a remote container
container_file_writeWrite a file to a remote container
container_file_listList directory contents on a remote container

Container Management

ToolDescription
container_listList all connected satellite containers
container_statusGet system status (memory, disk, uptime) of a container
container_kickDisconnect a container (it will auto-reconnect)
container_createCreate a new Adom container (repo + curium + container)
container_install_cmdGenerate the one-liner install command for a satellite
container_dashboardDisplay the Conduit dashboard in Gallia Viewer

Persistent Shell Sessions

The container_shell_* tools give Claude Code a persistent interactive shell on any satellite container. Unlike container_exec (which spawns a new process per call), shell sessions preserve state across calls:

container_shell_start("service-test1")        → sessionId
container_shell_exec(sessionId, "cd /tmp")
container_shell_exec(sessionId, "pwd")        → /tmp         (cwd persists!)
container_shell_exec(sessionId, "export FOO=bar")
container_shell_exec(sessionId, "echo $FOO")  → bar          (env vars persist!)
container_shell_exec(sessionId, "whoami")     → adom
container_shell_stop(sessionId)

How It Works

  1. shell_start spawns a PTY on the satellite agent (real terminal via script -qfc 'bash -i')
  2. shell_exec wraps each command with SOH-byte sentinel markers, sends it as PTY input, and waits for the output between the markers
  3. The server buffers PTY output and uses pattern matching to detect command completion and extract the result
  4. Sessions auto-cleanup after 30 minutes of inactivity

This approach gives Claude Code a true interactive shell experience — including sudo, package management, process control, and anything else you'd do in a terminal — all through the MCP tool interface.


Dashboard (Gallia Viewer)

Open the interactive management dashboard:

container_dashboard()

The dashboard has three tabs:

  • Shell — Full interactive xterm.js terminal connected to a remote container via PTY WebSocket relay. Supports curses-based applications (nano, vim, htop, etc.)
  • Terminal — Simple command execution with output display (non-interactive)
  • Claude Prompts — Pre-built prompts for common container management tasks

The left panel shows all connected containers with name, hostname, IP, capabilities, and connection age.


Installing the Agent

One-liner install (direct network)

curl -sL http://<MAIN_IP>:8800/agent/install | CC_NAME=my-service bash

Proxy install (cross-container via Coder proxy)

curl -sL https://coder.<SLUG>.containers.adom.inc/proxy/8800/agent/install | \
  CC_BASE_URL=https://coder.<SLUG>.containers.adom.inc/proxy/8800 \
  CC_NAME=my-service sudo -E bash

The install script:

  1. Creates /opt/container-conduit/ owned by adom
  2. Downloads agent.js and package.json from the main container
  3. Runs npm install
  4. Writes config.json with WebSocket URL and token
  5. Starts the agent from ~/project
  6. Adds a cron @reboot entry for auto-start

Environment Variables

VariableDefaultDescription
CC_HOST(required)Main container IP
CC_PORT8800Main container WS port
CC_TOKENadom-container-token-2025Authentication token
CC_NAME$(hostname)Container name shown in dashboard
CC_BASE_URLhttp://$CC_HOST:$CC_PORTOverride download URL (for proxy setups)
CC_WS_URLauto-detectedOverride WebSocket URL (e.g. wss://...)

Auto-Start

Container Conduit registers with the Gallia auto-start system via service.json. Both gallia-start.sh and gallia-watchdog.sh auto-discover this manifest — the server starts on boot and restarts automatically if it crashes.


Troubleshooting

SymptomCauseFix
Agent can't connectInternal hostname not routableUse CC_BASE_URL with the Coder proxy URL
\r': command not found during installCRLF line endingsRun sed -i 's/\r$//' /opt/container-conduit/agent.js
Permission denied on /opt/container-conduitScript not run with sudoUse sudo -E bash to preserve env vars
Dashboard shows 0 containersAPI URL detection failsRestart MCP server (it injects __CONDUIT_API_BASE__)
PTY timeout on ConnectAgent running old codeRestart agent with updated agent.js
Shell tab WebSocket errorPort 8801 not reachable via proxyEnsure server.js binds 8801 to 0.0.0.0

Skill Source

Edit AI Skill
---
name: container-conduit
author: Noah
description: "Use when the user wants to manage remote containers via Container Conduit — connecting satellite containers, running commands remotely, transferring files, opening interactive PTY shells, viewing the Conduit dashboard, or installing the Conduit agent on new containers. Covers the WebSocket bridge between a main Gallia container and satellite Adom containers."
---

# Container Conduit

Container Conduit is a WebSocket bridge that connects a main Gallia container to one or more satellite Adom containers. It enables remote command execution, file transfer, system status queries, and interactive PTY terminal sessions — all from Claude Code or the Gallia Viewer dashboard.

## Architecture

```
Main Container (Gallia)                  Satellite Container(s)
  server.js (WS port 8800)  ←──WS──→  agent.js
  HTTP API  (port 8801)                   ↑
       ↑                              install.sh (bootstrap)
  MCP tools (mcp/server.js)
       ↑
  Claude Code / Dashboard
```

- **server.js** — WebSocket server on port 8800 that accepts agent connections, plus an HTTP API on port 8801 for MCP tools and the dashboard
- **agent.js** — Lightweight satellite agent that connects back to the main container and handles exec, file, status, and PTY commands
- **mcp/server.js** — MCP stdio server exposing Container Conduit tools to Claude Code
- **dashboard.html** — Interactive management dashboard displayed in Gallia Viewer with Shell (xterm.js), Terminal, and Prompts tabs

## Key Files

| File | Location | Purpose |
|------|----------|---------|
| `server.js` | `services/container-conduit/server.js` | Main WS+HTTP server |
| `agent.js` | `services/container-conduit/agent/agent.js` | Satellite agent |
| `install.sh` | `services/container-conduit/agent/install.sh` | One-line agent bootstrap |
| `mcp/server.js` | `services/container-conduit/mcp/server.js` | MCP tool definitions |
| `dashboard.html` | `services/container-conduit/dashboard.html` | GV management dashboard |
| `service.json` | `services/container-conduit/service.json` | Auto-start manifest |

## MCP Tools

All tools are prefixed `container_` in the MCP server:

| Tool | Description |
|------|-------------|
| `container_list` | List all connected satellite containers |
| `container_exec` | Execute a shell command on a specific container |
| `container_exec_all` | Execute a command on ALL connected containers |
| `container_file_read` | Read a file from a remote container (base64) |
| `container_file_write` | Write a file to a remote container (base64) |
| `container_file_list` | List directory contents on a remote container |
| `container_status` | Get system status (memory, disk, uptime) of a container |
| `container_kick` | Disconnect a container (it will auto-reconnect) |
| `container_shell_start` | Start a persistent interactive shell session (returns sessionId) |
| `container_shell_exec` | Run a command in a persistent shell (state persists across calls) |
| `container_shell_stop` | Stop a persistent shell session |
| `container_dashboard` | Display the Conduit dashboard in Gallia Viewer |
| `container_create` | Create a new Adom container (repo + curium + container) |
| `container_install_cmd` | Generate the one-liner install command for a satellite |

## Installing the Agent on a Satellite Container

### One-liner install (direct network)

```bash
curl -sL http://<MAIN_IP>:8800/agent/install | CC_NAME=my-service bash
```

### Proxy install (Coder proxy for cross-container communication)

```bash
curl -sL https://coder.<SLUG>.containers.adom.inc/proxy/8800/agent/install | \
  CC_BASE_URL=https://coder.<SLUG>.containers.adom.inc/proxy/8800 \
  CC_NAME=my-service sudo -E bash
```

The install script:
1. Creates `/opt/container-conduit/` owned by `adom`
2. Downloads `agent.js` and `package.json` from the main container
3. Runs `npm install`
4. Writes `config.json` with WebSocket URL and token
5. Starts the agent from `~/project`
6. Adds a cron `@reboot` entry for auto-start

### Environment variables

| Variable | Default | Description |
|----------|---------|-------------|
| `CC_HOST` | (required) | Main container IP |
| `CC_PORT` | `8800` | Main container WS port |
| `CC_TOKEN` | `adom-container-token-2025` | Authentication token |
| `CC_NAME` | `$(hostname)` | Container name shown in dashboard |
| `CC_BASE_URL` | `http://$CC_HOST:$CC_PORT` | Override download URL (for proxy setups) |
| `CC_WS_URL` | auto-detected | Override WebSocket URL (e.g. `wss://...`) |

## Dashboard (Gallia Viewer)

Open the dashboard via MCP tool:

```
container_dashboard()
```

The dashboard has three tabs:

1. **Shell** — Interactive xterm.js terminal connected to a remote container via PTY WebSocket relay. Supports full TTY (nano, vim, htop, etc.)
2. **Terminal** — Simple command execution with output display (non-interactive)
3. **Claude Prompts** — Pre-built prompts for common container management tasks

The left panel shows all connected containers with name, hostname, IP, capabilities, and connection age.

## Persistent Shell Sessions (MCP)

The `container_shell_*` tools give Claude Code a persistent interactive shell on any satellite container. Unlike `container_exec` (which spawns a new process per call), shell sessions preserve state:

```
container_shell_start("service-test1")  → sessionId
container_shell_exec(sessionId, "cd /tmp")
container_shell_exec(sessionId, "pwd")  → /tmp  (cwd persists!)
container_shell_exec(sessionId, "export FOO=bar")
container_shell_exec(sessionId, "echo $FOO")  → bar  (env vars persist!)
container_shell_stop(sessionId)
```

**How it works:** The server spawns a PTY on the agent, then wraps each command with SOH-byte sentinel markers to detect completion and extract output. Sessions auto-cleanup after 30 minutes of inactivity.

## PTY Terminal (Dashboard)

The Shell tab provides a full interactive terminal via:

```
Dashboard (xterm.js) → WS port 8801 /pty → server.js relay → agent.js → script -qfc 'bash -i' /dev/null
```

The agent uses `script` to allocate a real PTY without requiring `node-pty`. This supports curses-based applications (nano, vim, htop, etc.).

## Auto-Start

The `service.json` manifest registers Container Conduit with the gallia auto-start system:

```json
{
  "name": "container-conduit",
  "port": 8800,
  "health": "tcp",
  "start": "node server.js",
  "cwd": "."
}
```

Both `gallia-start.sh` and `gallia-watchdog.sh` auto-discover this manifest. The server starts on boot and restarts automatically if it crashes.

## Troubleshooting

| Symptom | Cause | Fix |
|---------|-------|-----|
| Agent can't connect | Internal hostname not routable between containers | Use `CC_BASE_URL` with the Coder proxy URL |
| `\r': command not found` during install | CRLF line endings in agent files | Run `sed -i 's/\r$//' /opt/container-conduit/agent.js` |
| Permission denied on `/opt/container-conduit` | Script not run with sudo | Use `sudo -E bash` to preserve env vars |
| Dashboard shows 0 containers | API URL detection fails in srcdoc iframe | MCP server injects `__CONDUIT_API_BASE__` — restart MCP if stale |
| PTY timeout on Connect | Agent running old code without PTY support | Restart agent with updated `agent.js` |
| Shell tab WebSocket error | Port 8801 not reachable via proxy | Ensure `server.js` binds 8801 to `0.0.0.0` |

Sub-Skills
?
What are Sub-Skills?

Sub-skills are community-contributed AI skill extensions for this component. They teach AI assistants about specific tools, configurators, or workflows.

Examples:

  • A manufacturer’s configuration tool for a motor controller
  • A community-written design guide for an amplifier circuit
  • An automated test/validation script for a sensor module

How to add one: Click Add Sub-Skill, provide the URL to your skill and a brief description. Submissions are reviewed by the Adom team before going live.

No sub-skills yet. Be the first to contribute one!

0 revisions · Updated 2026-03-05 00:49:03