Skip to content

Repository files navigation

Agent Fleet β€” VS Code Extension

Prototype sibling-folder fork for testing a tree-first workbench: a compact hierarchy sidebar with role badges, summaries, and an inline inspector.

Before:

πŸ€– $\color{red}{Agent}$

After:

πŸ€– $\color{red}{Agent}$ .new( πŸ–₯️ $\color{green}{Terminal}$ .new( πŸ€– $\color{blue}{Agent}$ ) )

An agent opens a terminal. Inside, another agent wakes up. It opens more terminals. More agents wake up. All the way down.

while (true) {
  agent.createTerminal().launchAgent();  // you are here
}

The missing agent.fork() for Claude Code, Codex CLI, Gemini CLI, and Copilot CLI.

                          You (watching)
                               β”‚
                          β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”
                          β”‚ Agent 0 β”‚  ← your Copilot CLI session
                          β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
               β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β” β”Œβ”€β”€β”΄β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”΄β”€β”€β”€β”€β”
               β”‚ Agent 1 β”‚ β”‚ ...  β”‚ β”‚ Agent N β”‚  ← each in a visible terminal
               β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”          β”Œβ”€β”€β”΄β”€β”€β”€β”
       β”Œβ”€β”€β”€β”€β”΄β”€β”€β” β”Œβ”€β”€β”΄β”€β”€β”€β” β”Œβ”΄β”€β”€β”€β”€β”€β”   β”‚ ...  β”‚
       β”‚ 1.1   β”‚ β”‚ 1.2  β”‚ β”‚ 1.3  β”‚   β””β”€β”€β”€β”€β”€β”€β”˜  ← agents spawning agents
       β””β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”˜

Each agent can see, type, read, and spawn more of itself. You just watch.

Features

  • πŸ–₯️ Create visible terminals β€” agent opens new terminal tabs you can see
  • ⌨️ Send commands β€” agent types commands, you watch in real-time
  • πŸ“– Read output β€” agent reads terminal output with cursor-based incremental reads
  • πŸ”‘ Send keystrokes β€” Ctrl+C, arrow keys, function keys, etc.
  • πŸ“Έ Screenshot β€” capture current terminal screen content
  • πŸ”„ Multiple sessions β€” manage any number of terminals simultaneously
  • πŸ”’ Localhost only β€” server binds to 127.0.0.1, no remote access
  • 🌲 Hierarchical workbench β€” sidebar webview renders a tree-first agent hierarchy with window/group/manager/worker/subagent semantics
  • 🧭 Compact hierarchy navigation β€” collapse, pin, filter, subtree rollups, right-aligned role badges, and inline summaries for large orchestration trees
  • πŸ“‹ Inline inspector β€” inspect the currently selected node's status, children, terminal binding, and subtree health below the tree

Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    VS Code                           β”‚
β”‚                                                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚         Agent Fleet Extension               β”‚  β”‚
β”‚  β”‚                                                β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  β”‚
β”‚  β”‚  β”‚  Terminal     β”‚    β”‚  MCP Server (SDK)    β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  Manager      │◄───│  + HTTP transport    β”‚  β”‚  β”‚
β”‚  β”‚  β”‚  (VS Code     β”‚    β”‚  127.0.0.1:17580     β”‚  β”‚  β”‚
β”‚  β”‚  β”‚   API)        β”‚    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜               β”‚              β”‚  β”‚
β”‚  β”‚                                 β”‚ on activate: β”‚  β”‚
β”‚  β”‚      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚  β”‚
β”‚  β”‚      β”‚ 1. Write mcp-config.json            β”‚   β”‚  β”‚
β”‚  β”‚      β”‚ 2. Write ~/.agent-fleet-port    β”‚   β”‚  β”‚
β”‚  β”‚      β”‚ 3. Register VS Code MCP API         β”‚   β”‚  β”‚
β”‚  β”‚      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                    β”‚                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Terminal: copilot              β”‚              β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”             β”‚              β”‚  β”‚
β”‚  β”‚  β”‚  Copilot CLI   β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜              β”‚  β”‚
β”‚  β”‚  β”‚  reads mcp-    β”‚  POST /mcp (JSON-RPC)      β”‚  β”‚
β”‚  β”‚  β”‚  config.json   β”‚                            β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                            β”‚  β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”‚
β”‚  β”‚  Terminal: agent-controlled (visible to you)   β”‚  β”‚
β”‚  β”‚  Terminal: agent-controlled (visible to you)   β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                      β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  VS Code Copilot Chat (sidebar / agent mode)  β”‚  β”‚
β”‚  β”‚  Discovers via registerMcpServerDef... API     β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Installation

# Build
npm install && npm run build

# Package
npm run package

# Bump patch version, package, and install into regular VS Code
npm run install:local

Or press F5 in VS Code to launch the Extension Development Host for development.

Configuration

The extension auto-registers as an MCP server on activation. No manual setup needed.

It writes to ~/.copilot/mcp-config.json:

{
  "mcpServers": {
    "agent-fleet": {
      "type": "http",
      "url": "http://127.0.0.1:17580/mcp",
      "tools": ["*"]
    }
  }
}

It also writes ~/.agent-fleet-port with the port number for non-MCP discovery.

Extension Settings

Setting Default Description
agentFleet.port 17580 Preferred HTTP port (falls back to random if busy)
agentFleet.maxBufferSize 1048576 Max output buffer per terminal (bytes)
agentFleet.runnerAutoLaunch true Auto-launch and reconnect the local companion runner process on activation
agentFleet.logLevel info Log level: debug, info, warn, error

MCP Tools

The extension exposes three tool families:

  • Terminal tools (8): terminal_create, terminal_send, terminal_send_keys, terminal_type, terminal_read, terminal_list, terminal_close, terminal_screenshot
  • Runtime tools (3): runtime_type, runtime_send_keys, runtime_read
  • Graph tools (10): graph_create_group, graph_create_agent, graph_bind_agent, graph_import_terminal, graph_remove, graph_update, graph_move, graph_list, graph_stop_subtree, graph_retry

Terminal tools

Tool What it does Notes
terminal_create Create a visible VS Code terminal Returns both ephemeral terminalId and durable runtimeId metadata
terminal_send Write text directly to stdin Uses addNewline (default true)
terminal_send_keys Send control/navigation keys Good for interrupts and shell history
terminal_type Type through the xterm keyboard path Prefer for busy TUIs that need real typing semantics
terminal_read Read buffered output incrementally Supports since, waitMs, waitForOutput, waitForIdle, waitForString, raw, maxLines
terminal_list List tracked terminals Includes runtimeId, ownership, provenance, import policy, mode, and status
terminal_close Close a tracked terminal Clears the live binding
terminal_screenshot Return a text snapshot of recent output Uses maxLines

Graph tools

Tool What it does Notes
graph_create_group Create an organizational node Groups do not bind to terminals
graph_create_agent Create an agent node runtimeId is the canonical binding key
graph_bind_agent Bind/rebind an existing agent node terminalId is only an ephemeral fallback
graph_import_terminal Explicitly import a tracked terminal into the graph Promotes external/manual terminals to workbench/auto metadata before binding
graph_remove Remove a node/subtree Removes descendants too
graph_update Update label/role/status/summary Lightweight graph metadata edit
graph_move Reparent a node Supports sibling index
graph_list Read the hierarchy tree Returns terminal binding metadata on agent nodes
graph_stop_subtree Stop all bound terminals in a subtree For graph-managed terminals
graph_retry Recreate a stopped agent runtime, or launch an idle runner-backed agent Reuses the node's retained runtimeId when present

Runtime tools

These tools target the extension-owned runner/PTy execution plane rather than VS Code's built-in terminal tabs.

Tool What it does Notes
runtime_type Type text into a runner-backed runtime by runtimeId TUI-safe path for Copilot/Claude-style workers; optional submit presses Enter
runtime_send_keys Send control/navigation keys to a runner-backed runtime Use for Enter, Escape, Ctrl+C, arrows, etc.
runtime_read Read buffered output from a runner-backed runtime Supports since, waitFor*, maxLines, and optional raw ANSI output

Phase 2 runtime model

  • Tracked terminals and graph nodes are different things. The terminal tracker can know about a terminal even when no graph node exists for it yet.
  • Graph nodes are not terminal nodes. Agent nodes may bind to terminals, but the graph itself models agents/groups, not raw terminals.
  • runtimeId is the durable identity. terminalId is only the live VS Code handle for the current session/window.
  • External terminals are not auto-imported by default. They remain tracked-but-outside-the-graph until explicitly imported with graph_import_terminal.

Requirements

  • VS Code 1.93+ (Shell Integration API)
  • PowerShell or Bash with shell integration enabled
  • Node.js 18+ (bundled with VS Code)

How It Works

  1. On activation, the extension starts an HTTP server on 127.0.0.1:17580
  2. It registers itself in ~/.copilot/mcp-config.json so Copilot CLI discovers it
  3. The terminal manager adopts existing VS Code terminals into the tracked-terminal registry
  4. Persisted workbench graph/view state is rehydrated
  5. Startup backfill only auto-imports tracked terminals whose metadata says they belong in the graph
  6. Copilot CLI (or any MCP client) sends JSON-RPC requests to /mcp
  7. The extension creates/controls real VS Code terminal tabs via the VS Code API
  8. All terminals are visible β€” you see exactly what the agent is doing
  9. On deactivation, the extension unregisters and cleans up

Persistence and restore

  • The extension persists graph state + workbench UI state, not live PTY sessions.
  • Persisted agent nodes keep their runtimeId, but persisted terminalId bindings are cleared.
  • Nodes that were previously bound to running terminals come back as disconnected until they are rebound.
  • Startup reconciliation collapses duplicate runtimeId bindings and clears any stale live-terminal claims before the tree rehydrates against the current terminal registry.
  • Existing VS Code terminals are tracked again on startup, but adopted external terminals stay outside the graph unless they match auto-import policy or you explicitly import them.
  • Closing a bound terminal clears the live terminalId while keeping the node's runtimeId, which is what later retry/rebind flows use.

Smoke flow (Phase 2)

Use this flow to verify the current implementation without assuming more than the code does today.

  1. Install / reload
    • Run npm install
    • Run npm run build
    • Press F5 to launch the Extension Development Host, or run npm run install:local to bump the patch version and install the VSIX into regular VS Code
    • In the host window, run Developer: Reload Window once to verify activation + rehydration
  2. Confirm MCP registration
    • Check ~/.copilot/mcp-config.json for agent-fleet
    • Check ~/.agent-fleet-port or the Agent Fleet output channel if the preferred port was busy
  3. Create a workbench-owned runtime
    • Call terminal_create without overriding ownership metadata
    • Confirm terminal_list shows runtimeKind: "vscode-terminal", ownership: "workbench", provenance: "created" (or "recovered" when reusing a runtimeId), and graphImportPolicy: "auto"
  4. Bind by runtimeId
    • Call graph_create_agent or graph_bind_agent with the terminal's runtimeId
    • Confirm the node reflects runtimeId, runtimeKind: "vscode-terminal", and the current terminalId
    • If you later close/retry the terminal, confirm the node keeps the same runtimeId
  5. Verify restart / restore behavior
    • Reload the window
    • Confirm the graph reappears, but previously bound nodes restore as disconnected until rebound
    • Confirm tracked terminal count can differ from graph node count after reload
  6. Verify auto-import policy
    • Workbench-created or recovered terminals with graphImportPolicy: "auto" are eligible for startup backfill into the graph
    • Adopted/external terminals default to manual import and should remain tracked-but-outside-the-graph after reload
  7. Verify manual import / promote path
    • Open or keep an external terminal that the extension tracks
    • Call terminal_list and identify its terminalId
    • Call graph_import_terminal with that terminalId
    • Confirm the terminal is now represented by an agent node and the bound metadata is promoted into the workbench/auto path
  8. Verify focus behavior
    • terminal_send / terminal_send_keys preserve editor focus while sending input
    • terminal_type intentionally focuses the terminal because it uses the active-terminal typing path

Current policy summary

  • Auto-import on startup: only terminals that are already workbench-owned/recovered and marked graphImportPolicy: "auto"
  • Tracked but not in graph: adopted external terminals
  • Explicit import path: terminal_list β†’ graph_import_terminal
  • Canonical rebind concept: runtimeId
  • Current VS Code terminal backend: runtimeKind: "vscode-terminal"
  • Phase 3 runner backend: runtimeKind: "runner-process" is now part of graph binding and the custom runtime panel flow
  • Phase 3 host bridge: the extension auto-discovers / auto-launches the local runner-process companion and keeps a reconnectable host-side bridge ready

Smoke flow (Phase 3 MVP)

Use this flow to verify the custom execution-plane slice introduced in Phase 3.

  1. Build the extension + smoke targets
    • npm run build
  2. Run the backend/runtime smoke
    • npm run smoke:phase3
    • This validates:
      • graph_create_agent-style idle runner intent
      • graph_retry launching a real runner-process shell
      • input/output round-trips against the live shell
      • runtime-level TUI-safe typing, keypress, and read flows against a second runner runtime
      • resize through the runner bridge
      • reconnect by rebuilding the host-side service against the same runner process
      • stop + retry while retaining the same runtimeId
  3. Manual panel sanity check in VS Code
    • Launch the Extension Development Host (F5)
    • Create or recover a runner-backed graph node
    • Use the sidebar's focus/open action on that node
    • Confirm the dedicated runtime terminal panel hydrates output, accepts line input, and reflects stop state changes

Development

# Install dependencies
npm install

# Build (one-time)
npm run build

# Watch mode (rebuild on change)
npm run watch

# Launch Extension Development Host
# Press F5 in VS Code

# Package for distribution
npm run package

# Local install into regular VS Code
# Automatically bumps 0.3.0 -> 0.3.1 -> 0.3.2 ...
npm run install:local

Project Structure

src/
β”œβ”€β”€ extension.ts              # Extension entry point, lifecycle management
β”œβ”€β”€ runner/
β”‚   β”œβ”€β”€ client.ts             # Host-side JSON-RPC client for the companion runner
β”‚   β”œβ”€β”€ launcher.ts           # Discovery + auto-launch/bootstrap for the local runner process
β”‚   β”œβ”€β”€ service.ts            # Lightweight lifecycle/cache bridge owned by the extension host
β”‚   β”œβ”€β”€ main.ts               # Companion runner entry point
β”‚   └── hostBridgeSmoke.ts    # Narrow dev smoke for host↔runner round-trips
β”œβ”€β”€ config/
β”‚   └── autoRegister.ts       # MCP server registration (config file + VS Code API)
β”œβ”€β”€ graph/
β”‚   β”œβ”€β”€ graphManager.ts       # Persisted graph state + binding sanitization on save
β”‚   β”œβ”€β”€ mcpTools.ts           # graph_* MCP tool registrations
β”‚   β”œβ”€β”€ orchestrator.ts       # Agent graph lifecycle, import, bind, retry, startup backfill
β”‚   └── workbenchStateStore.ts # Workspace-state persistence/rehydration
β”œβ”€β”€ server/
β”‚   β”œβ”€β”€ httpServer.ts         # HTTP server with auto-restart + socket tracking
β”‚   └── mcpServer.ts          # MCP tool definitions (via @modelcontextprotocol/sdk)
β”œβ”€β”€ terminal/
β”‚   β”œβ”€β”€ manager.ts            # Terminal lifecycle, tracking, adoption, import metadata
β”‚   β”œβ”€β”€ outputBuffer.ts       # Ring buffer with cursor-based reads + waitFor*
β”‚   β”œβ”€β”€ shellIntegration.ts   # VS Code Shell Integration API wrapper
β”‚   β”œβ”€β”€ pseudoTerminal.ts     # PTY mode for advanced terminal control
β”‚   └── runtimeMetadata.ts    # ownership/provenance/graph import policy defaults
β”œβ”€β”€ webview/
β”‚   β”œβ”€β”€ agentTreeProtocol.ts     # Host/webview message contract
β”‚   β”œβ”€β”€ agentTreeViewProvider.ts # Thin host bridge: lifecycle, sync, actions, terminal focus
β”‚   └── agentTreeWebviewHtml.ts  # Bundled frontend payload (HTML/CSS/JS)
└── utils/
    β”œβ”€β”€ logger.ts             # Structured leveled logging to OutputChannel
    └── ansiStrip.ts          # Comprehensive ANSI escape sequence removal

Troubleshooting

Server not starting

Check the output channel: View β†’ Output β†’ Agent Fleet

Copilot CLI can't find the server

Verify the config: cat ~/.copilot/mcp-config.json

Expected:

{
  "mcpServers": {
    "agent-fleet": {
      "type": "http",
      "url": "http://127.0.0.1:17580/mcp",
      "tools": ["*"]
    }
  }
}

Port conflict

If port 17580 is busy, the extension auto-selects a random port. Check ~/.agent-fleet-port for the actual port, or look in the Output channel.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages