# How the Brainstorming Skill Integrates with External Visual Companion Servers in OpenAI Plugins

> Learn how the brainstorming skill in OpenAI plugins uses shell scripts to integrate with external visual companion servers for rendering tasks. Explore state file connections.

- Repository: [OpenAI/plugins](https://github.com/openai/plugins)
- Tags: internals
- Published: 2026-06-11

---

**The brainstorming skill hands off visual rendering tasks to a lightweight Node.js companion server by executing shell scripts that manage the server's lifecycle, with connection details exchanged via a JSON state file in the project's `.superpowers/brainstorm/` directory.**

The `brainstorming` skill in the `openai/plugins` repository supports two distinct modes of operation: pure-text brainstorming within the LLM chat interface, and visual-companion mode that leverages external scripts to generate mock-ups and diagrams. This article examines how the skill orchestrates seamless integration with external processes without requiring manual code changes, using specification files and shell scripts to manage a temporary Node.js server.

## Understanding the Brainstorming Skill Architecture

Located under `plugins/superpowers/skills/brainstorming`, the skill is designed to run in two distinct modes. In **pure-text brainstorming**, all interaction stays inside the LLM chat. In **visual-companion mode**, the skill hands off the session to a lightweight companion server that renders mock-ups, diagrams, and other visual assets. The hand-off is orchestrated entirely by the skill's specification files found in [`SKILL.md`](https://github.com/openai/plugins/blob/main/SKILL.md) and [`visual-companion.md`](https://github.com/openai/plugins/blob/main/visual-companion.md), requiring no manual code modifications to enable external script integration.

## Step-by-Step Integration Flow

The integration follows a strict lifecycle managed through shell scripts and state files. Each step is governed by specific source files in the repository.

### Step 1: User Accepts Visual Help

The skill initiates visual mode by sending a single-message offer containing the visual-companion invitation, as defined in [`plugins/superpowers/skills/brainstorming/SKILL.md`](https://github.com/openai/plugins/blob/main/plugins/superpowers/skills/brainstorming/SKILL.md). The user must explicitly reply "yes" to trigger the external server launch. This explicit opt-in ensures that external script execution only occurs with user consent.

### Step 2: Companion Server Startup

Upon user agreement, the skill executes [`plugins/superpowers/skills/brainstorming/scripts/start-server.sh`](https://github.com/openai/plugins/blob/main/plugins/superpowers/skills/brainstorming/scripts/start-server.sh). This bash wrapper spawns a Node.js server (`scripts/server.cjs`) in the background. The script receives `--project-dir` (the root of the current LLM project) as a parameter, establishing the working context for the session.

### Step 3: State Directory Preparation

The startup script prepares a dedicated state directory under `.superpowers/brainstorm/<session-id>/` within the project root. All generated files are stored here, ensuring they survive restarts and remain scoped to the specific brainstorming session. According to [`plugins/superpowers/skills/brainstorming/visual-companion.md`](https://github.com/openai/plugins/blob/main/plugins/superpowers/skills/brainstorming/visual-companion.md), this directory structure allows the server to maintain persistence without interfering with the host project's version control.

### Step 4: Server Publishes Connection Info

On startup, the server writes a JSON blob to `$STATE_DIR/server-info` containing the host, port, and optional secret token. This file serves as the single source of truth for the LLM to determine how to reach the companion. The server dynamically selects an available port at runtime rather than using hard-coded values, preventing conflicts with other services.

### Step 5: LLM-to-Server Communication

Subsequent brainstorming turns include HTTP `GET` and `POST` requests to the URL read from `server-info`. The server returns HTML frames based on [`plugins/superpowers/skills/brainstorming/scripts/frame-template.html`](https://github.com/openai/plugins/blob/main/plugins/superpowers/skills/brainstorming/scripts/frame-template.html), embedding mock-ups, SVG diagrams, or static images generated by downstream skills. Each request contains sufficient context (session ID, token) to enable stateless communication.

### Step 6: Session Cleanup

When the user signals the end of brainstorming or the LLM transitions to the `writing-plans` skill, the skill executes [`plugins/superpowers/skills/brainstorming/scripts/stop-server.sh`](https://github.com/openai/plugins/blob/main/plugins/superpowers/skills/brainstorming/scripts/stop-server.sh). This script terminates the background Node process and removes the temporary state directory, unless a persistent `--project-dir` was specified to retain visual assets.

## Key Integration Mechanisms

The integration relies on four architectural principles that ensure reliable operation:

- **Dynamic Port Allocation**: The server selects an available port at runtime and publishes it via `server-info`, eliminating port conflicts and manual configuration.
- **Project-Scoped Persistence**: By passing `--project-dir`, visual assets are stored in the project's `.superpowers/brainstorm/` folder, which should be added to `.gitignore` to prevent accidental commits of generated files.
- **Stateless Communication**: Each HTTP call contains enough context (session ID, token) for the server to serve correct assets without maintaining long-lived in-process state.
- **Skill Isolation**: After brainstorming, the only permitted next skill is `writing-plans`; the visual companion cannot be invoked again unless a new brainstorming round starts.

## Practical Implementation Examples

The following examples demonstrate how to interact with the visual companion server manually, though the skill handles these operations automatically.

Start the visual companion from the skill runner:

```bash
PROJECT_ROOT="/path/to/your/project"
scripts/start-server.sh --project-dir "$PROJECT_ROOT"

```

Read the server connection details (LLM-side implementation pattern):

```python
import json
import pathlib

state_dir = pathlib.Path(".superpowers/brainstorm") / "<session-id>"
info_path = state_dir / "server-info"

with open(info_path) as f:
    info = json.load(f)
    
base_url = f"http://{info['host']}:{info['port']}"

```

Request a visual asset rendering via the server's REST API:

```bash
curl -X POST "$BASE_URL/render" \
     -H "Content-Type: application/json" \
     -d '{"type":"mockup","data":{...}}'

```

Terminate the server and clean up resources:

```bash
scripts/stop-server.sh --project-dir "$PROJECT_ROOT"

```

## Summary

- The brainstorming skill in `openai/plugins` supports visual-companion mode through automated shell script execution.
- [`scripts/start-server.sh`](https://github.com/openai/plugins/blob/main/scripts/start-server.sh) launches a Node.js server (`scripts/server.cjs`) that publishes connection details to `.superpowers/brainstorm/<session-id>/server-info`.
- Communication occurs via stateless HTTP requests to dynamically assigned ports, with HTML frames rendered using [`scripts/frame-template.html`](https://github.com/openai/plugins/blob/main/scripts/frame-template.html).
- [`scripts/stop-server.sh`](https://github.com/openai/plugins/blob/main/scripts/stop-server.sh) handles graceful shutdown and cleanup, while [`agents/openai.yaml`](https://github.com/openai/plugins/blob/main/agents/openai.yaml) configures the LLM's decision-making during the brainstorming session.
- Visual assets persist in project-scoped directories when `--project-dir` is specified, enabling seamless integration with external diagram and mock-up generation tools.

## Frequently Asked Questions

### What happens if the visual companion server crashes during a session?

If the Node.js process terminates unexpectedly, the `server-info` file remains in the state directory, but subsequent HTTP requests from the LLM will fail. The skill specification in [`SKILL.md`](https://github.com/openai/plugins/blob/main/SKILL.md) does not currently define automatic restart behavior; the user must manually restart the session or the skill runner must re-execute [`scripts/start-server.sh`](https://github.com/openai/plugins/blob/main/scripts/start-server.sh) to recreate the server process and regenerate the connection file.

### Can I configure a fixed port for the visual companion server?

No, the implementation in `scripts/server.cjs` intentionally avoids hard-coded ports. The server binds to an available ephemeral port at runtime and publishes this information to `$STATE_DIR/server-info`. This design prevents port conflicts when multiple brainstorming sessions run concurrently or when other services occupy standard ports.

### How do I persist visual assets between brainstorming sessions?

Pass the `--project-dir` argument when running [`scripts/start-server.sh`](https://github.com/openai/plugins/blob/main/scripts/start-server.sh), pointing to your project's root directory. Generated files are stored under `.superpowers/brainstorm/<session-id>/` within that directory. To retain assets indefinitely, avoid running [`scripts/stop-server.sh`](https://github.com/openai/plugins/blob/main/scripts/stop-server.sh) with cleanup flags, or copy files from the state directory before initiating the stop script. Remember to add `.superpowers/` to your `.gitignore` file.

### Is the communication between the LLM and the visual companion server secure?

The server writes an optional secret token to the `server-info` JSON file alongside the host and port. Subsequent HTTP requests from the LLM should include this token in headers for authentication. However, as implemented in `plugins/superpowers/skills/brainstorming`, the server runs on localhost by default, minimizing exposure to external networks. For production deployments, additional reverse proxy configuration or TLS termination would be required beyond the basic [`start-server.sh`](https://github.com/openai/plugins/blob/main/start-server.sh) implementation.