Agent Orchestrator

April 4, 2026 · View on GitHub

VS Code extension for managing multiple AI coding agents in isolated devcontainers. Each agent gets its own git clone, container, and port range — so agents can work on different tasks in parallel without stepping on each other.

Built as a Serverpod specialist: the orchestrator understands the Serverpod project structure and automatically injects gitignored config files (secrets, environment, volume mounts) into each agent's clone.

How It Works

┌─────────────┐     launch "auth"      ┌──────────────────────────┐
│  VS Code     │ ──────────────────────▶│  .claude/worktrees/auth/ │  (git clone)
│  Sidebar     │                        │  .devcontainer/.env      │  (ports + mode)
│              │     devpod up          │  passwords.yaml          │  (copied from host)
│  Agents:     │ ──────────────────────▶│  .env                    │  (copied from host)
│   ● auth     │                        └──────────┬───────────────┘
│   ○ redesign │                                   │
└─────────────┘                                    ▼
                                        ┌──────────────────────────┐
                                        │  DevPod Container        │
                                        │  agent-auth              │
                                        │  ports: 8180, 8181, ...  │
                                        └──────────────────────────┘
  1. Launch — creates a git clone on branch agent/{name}, allocates unique ports, writes .devcontainer/.env, copies host secrets
  2. Open in Container — runs devpod up to build and start the container with an IDE
  3. Shell — ensures the container is running, then opens an SSH session
  4. Diff / PR / Merge — review changes, create PRs, merge back when done
  5. Clean — removes clone, container, branch, and metadata

Prerequisites

ToolPurpose
DevPodContainer lifecycle management
GitClone and branch management
GitHub CLI (gh)PR creation and lookup
Docker (or compatible runtime)Container backend for DevPod

Installation

Install from a .vsix file:

npm run build                          # produces build/agent-orchestrator-X.Y.Z.vsix
code --install-extension build/agent-orchestrator-*.vsix

Or publish and install from a marketplace:

npm run publish-vscode                 # VS Code Marketplace
npm run publish-openvsx                # Open VSX Registry

Commands

All commands are available from the sidebar context menu and the command palette (Cmd+Shift+P).

CommandDescription
Launch AgentCreate a new agent with isolated clone and ports
Open in ContainerStart container and open IDE via DevPod
Open Agent ShellStart container if needed, then SSH into it
Show Agent DiffSide-by-side diff of agent's changes vs base branch
Show / Create PROpen existing PR or create a new one
Merge Agent BranchMerge agent's branch into a target branch
Stop AgentStop the container (preserves data)
Clean AgentRemove everything: clone, container, branch, metadata
Clean All AgentsClean all agents at once
Refresh Agent StatusManually refresh the sidebar

The Agent Orchestrator panel in the sidebar shows all agents with status icons:

  • Running — container is up
  • Stopped — container exists but is not running
  • Not Found — no container (needs Open in Container)

Expand an agent to see:

  • Branchagent/{name} (from {baseBranch})
  • Status — running / stopped / not found
  • Changed — number of modified files vs base branch
  • PR — link to GitHub PR (if one exists)
  • Ports — allocated API, Web, and DB ports

Configuration

Settings under agentOrchestrator.* in VS Code:

SettingDefaultDescription
defaultBaseBranchmasterBase branch for new agents
portStep100Port increment between agents
refreshIntervalSeconds15Auto-refresh interval (5–300s)
worktreeDir.claude/worktreesDirectory for git clones (relative to workspace)
agentsDir.claude/agentsDirectory for metadata JSON files (relative to workspace)

Port Allocation

Each agent gets a unique port range to avoid conflicts. Offset 0 is reserved for the main project's devcontainer.

Formula: port = base_port + (offset * portStep)

Project-specific port maps

Each project declares its port layout in .devcontainer/port-map.jsonc:

{
  // Each key is the env var name injected into docker-compose via .env.
  // Each value is the base port (offset 0 = host mode).
  // Agent ports are computed as: base + (offset * portStep).
  "API_PORT": 8080,
  "INSIGHTS_PORT": 8081,
  "WEB_PORT": 8082,
  "FLUTTER_DEBUG_PORT": 8083,
  "POSTGRES_PORT": 8090,
  "REDIS_PORT": 8091
}

The orchestrator reads this file at activation. If the file is missing, it falls back to the built-in defaults shown below.

Using distinct port ranges per project allows multiple devcontainer stacks to run simultaneously without port conflicts.

Default port map

Used when no port-map.jsonc is present:

PortOffset 0 (main)Offset 1 (agent 1)Offset 2 (agent 2)
API808081808280
Insights808181818281
Web808281828282
Flutter Debug808381838283
PostgreSQL809081908290
RustFS API900091009200
RustFS Console900191019201

Host File Injection

When launching an agent, the orchestrator copies gitignored files from the host project into the clone so the container has a working environment:

FilePurpose
easybiz_server/config/passwords.yamlServerpod secrets (API keys, DB passwords, SMTP, S3)
.envRoot environment variables (e.g. OLLAMA_CLOUD_API_KEY)
.devcontainer/docker-compose.override.ymlGenerated with absolute path for plugins volume mount

The .devcontainer/.env is also written with:

  • DEVCONTAINER_MODE=agent — tells init.sh to run in agent mode
  • PROJECT_NAME=agent_{name} — unique Postgres database per agent
  • Port assignments (see table above)

Architecture

src/
├── extension.ts                  # Activation, command registration, refresh timer
├── config.ts                     # VS Code settings reader
├── types.ts                      # Interfaces and enums
├── outputChannel.ts              # Output panel logging
├── statusBar.ts                  # "X/Y agents" status bar item
├── baseFileProvider.ts           # orch-base:// scheme for diff viewer
├── services/
│   ├── agentManager.ts           # Main orchestrator (launch, clean, diff, etc.)
│   ├── devpodService.ts          # DevPod CLI wrapper
│   ├── gitService.ts             # Git operations (clone, branch, diff, merge)
│   ├── ghService.ts              # GitHub CLI wrapper (PR list/create)
│   ├── metadataStore.ts          # JSON file persistence per agent
│   └── portAllocator.ts          # Port allocation and .env generation
├── commands/
│   ├── launch.ts                 # Launch Agent
│   ├── openContainer.ts          # Open in Container
│   ├── shell.ts                  # Open Agent Shell
│   ├── diff.ts                   # Show Agent Diff
│   ├── pr.ts                     # Show / Create PR
│   ├── merge.ts                  # Merge Agent Branch
│   ├── stop.ts                   # Stop Agent
│   ├── clean.ts                  # Clean Agent / Clean All
│   └── utils.ts                  # Agent picker helper
└── views/
    └── agentTreeProvider.ts      # Sidebar tree view

Development

npm install                        # Install dependencies
npm run esbuild-watch              # Watch mode (rebuilds on save)
# Press F5 in VS Code to launch Extension Development Host
npm run lint                       # ESLint
npm run compile                    # TypeScript type check
npm run build                      # Package .vsix to build/

Design Decisions

Git clones over worktrees — Worktrees store .git as a file pointing to the main repo via host-relative paths, which break inside containers. Clones have independent .git/ directories that work identically on host and in containers.

Relative paths for DevPod — DevPod interprets absolute and bare relative paths as git URLs. The ./ prefix signals "local folder".

Underscores in PROJECT_NAME — Agent names use kebab-case (auth-feature) but PROJECT_NAME uses underscores (agent_auth_feature) because hyphens are invalid SQL identifiers in PostgreSQL.

Serverpod specialist — The orchestrator knows about Serverpod's file layout (passwords.yaml, config structure, docker-compose) rather than being tech-stack agnostic. This eliminates the need for generic hook mechanisms and makes the injection reliable.

Per-project port maps — Different projects have different services (object storage, Redis, test databases, etc.), so the port layout can't be one-size-fits-all. Each project declares its ports in .devcontainer/port-map.jsonc, and the orchestrator applies the offset formula generically. A built-in default covers projects that don't provide the file.

License

MIT