# Visual Companion Technical Reference

Technical documentation for the GMD visual brainstorming companion server.

## Architecture

The visual companion is a zero-dependency HTTP server built on Node.js `http.createServer`. It is launched via a bash wrapper script that handles platform detection, argument parsing, and cleanup.

```
┌─────────────────────────────────────────┐
│  start-brainstorm-server.sh             │
│  - Parses --port, --project-dir         │
│  - Creates serving directory            │
│  - Detects platform for browser open    │
│  - Traps SIGINT/SIGTERM for cleanup     │
│                                         │
│  ┌───────────────────────────────────┐  │
│  │  Node.js HTTP Server (inline)     │  │
│  │  - GET /          → index.html    │  │
│  │  - GET /fragments → JSON listing  │  │
│  │  - POST /fragment → create file   │  │
│  │  - GET /*         → static files  │  │
│  └───────────────────────────────────┘  │
└─────────────────────────────────────────┘
```

**Components:**
- `scripts/start-brainstorm-server.sh` -- Bash wrapper with platform detection and lifecycle management
- Inline Node.js server -- HTTP server embedded in the bash script via `node -e`
- `index.html` -- Auto-generated landing page listing all fragments

## Endpoints

### GET / (index page)

Returns the landing page (`index.html`) which displays a card grid of all available fragments. The page auto-refreshes every 3 seconds to pick up new fragments.

### POST /fragment

Accepts raw HTML body content. Writes it to the serving directory as `fragment-{timestamp}.html`. Returns JSON with the URL and filename.

**Request:**
```
POST /fragment HTTP/1.1
Content-Type: text/html

<div style="padding: 2rem; font-family: sans-serif;">
  <h2>Login Page Wireframe</h2>
  <div style="border: 2px solid #ccc; padding: 1rem; width: 300px; margin: 1rem auto;">
    <div style="background: #eee; height: 40px; margin-bottom: 8px;"></div>
    <div style="background: #eee; height: 40px; margin-bottom: 8px;"></div>
    <div style="background: #af5fff; height: 40px; color: white; text-align: center; line-height: 40px;">Sign In</div>
  </div>
</div>
```

**Response:**
```json
{
  "url": "http://localhost:3333/fragment-1712345678901.html",
  "filename": "fragment-1712345678901.html"
}
```

### GET /fragments

Returns a JSON array of all fragment files with creation timestamps, sorted newest first.

**Response:**
```json
[
  { "name": "fragment-1712345678901.html", "created": "2026-04-10T12:00:00.000Z" },
  { "name": "fragment-1712345678900.html", "created": "2026-04-10T11:59:00.000Z" }
]
```

### GET /\* (static files)

Serves any file from the project directory. Supports HTML, CSS, JS, JSON, PNG, JPG, and SVG. Directory traversal is prevented by checking that resolved paths stay within the serving directory.

## How Agents Push Fragments

During a brainstorming session, agents generate HTML mockups and push them to the running server:

```bash
# Generate and push a wireframe fragment
curl -s -X POST http://localhost:3333/fragment \
  -H "Content-Type: text/html" \
  -d '<html><body><h1>Option A: Sidebar Layout</h1>...</body></html>'
```

The agent receives the URL in the response and can tell the user: "Check your browser for the wireframe at http://localhost:3333/fragment-1712345678901.html"

In practice, agents use the Bash tool to execute the curl command, composing the HTML inline.

## How Users View Mockups

1. The server auto-opens a browser tab on launch
2. The landing page shows a card grid of all fragments
3. Each card links to the full fragment HTML in a new tab
4. The landing page polls `/fragments` every 3 seconds for updates

Users do not need to run any commands. The browser tab stays open throughout the brainstorming session.

## Session Persistence

- **Fragments persist** for the duration of the server process
- **On shutdown** (Ctrl+C or SIGTERM), the cleanup handler removes all `fragment-*.html` files
- **The index.html** is preserved across sessions (only created if missing)
- **No database or state file** -- fragments are plain HTML files on disk
- Fragments are ephemeral by design. They support decision-making, not deliverables.

## Integration with Brainstorming Flow

The visual companion is offered (never forced) during brainstorming when:
- The phase involves UI/UX components
- Users mention layout, design, or visual preferences
- Comparing approaches with visual differences

**Typical flow:**
1. Brainstorming orchestrator detects visual context
2. Offers to launch visual companion: "Would you like me to start the visual companion for mockups?"
3. If accepted, launches server via Bash tool
4. Pushes HTML fragments as design options emerge
5. User reviews in browser, provides feedback
6. Decisions recorded in CONTEXT.md with fragment references
7. Server stopped when brainstorming concludes

## Example HTML Fragment -- Wireframe Mockup

```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Dashboard Layout Option A</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body { font-family: -apple-system, sans-serif; background: #f5f5f5; padding: 1rem; }
  .container { display: grid; grid-template-columns: 200px 1fr; grid-template-rows: 60px 1fr;
               gap: 1px; background: #ccc; min-height: 90vh; }
  .header { grid-column: 1 / -1; background: #af5fff; color: white;
            display: flex; align-items: center; padding: 0 1rem; font-weight: 700; }
  .sidebar { background: #2a2a4a; color: #d7afff; padding: 1rem; }
  .sidebar .nav-item { padding: 0.5rem; margin-bottom: 0.25rem; border-radius: 4px; }
  .sidebar .nav-item:hover { background: rgba(175, 95, 255, 0.2); }
  .main { background: white; padding: 1.5rem; }
  .card { background: #f9f9f9; border: 1px solid #eee; border-radius: 8px;
          padding: 1rem; margin-bottom: 1rem; }
  .card h3 { color: #333; margin-bottom: 0.5rem; }
  .placeholder { background: #eee; height: 120px; border-radius: 4px;
                 display: flex; align-items: center; justify-content: center; color: #999; }
</style>
</head>
<body>
  <div class="container">
    <div class="header">GMD Dashboard -- Option A (Sidebar)</div>
    <div class="sidebar">
      <div class="nav-item">Overview</div>
      <div class="nav-item">Projects</div>
      <div class="nav-item">Settings</div>
    </div>
    <div class="main">
      <div class="card">
        <h3>Active Projects</h3>
        <div class="placeholder">Chart placeholder</div>
      </div>
      <div class="card">
        <h3>Recent Activity</h3>
        <div class="placeholder">Activity feed placeholder</div>
      </div>
    </div>
  </div>
</body>
</html>
```

## Platform-Specific Notes

| Platform | Browser Open | Server | Notes |
|----------|-------------|--------|-------|
| macOS | `open` | Node.js | Works out of the box |
| Linux | `xdg-open` | Node.js | Requires xdg-utils for browser open |
| Windows (Git Bash) | `start` | Node.js | Detects MINGW/MSYS/CYGWIN |
| Windows (PowerShell) | Not supported directly | Node.js | Use the bash script from Git Bash |

The server itself (Node.js) works identically across all platforms. Only the browser-open mechanism varies.

## Security Considerations

- **Directory traversal prevention**: All file paths are resolved and checked against the serving directory root
- **Local only**: Server binds to localhost (not 0.0.0.0) by default
- **No authentication**: The server is intended for local development use only
- **Fragment injection**: POST /fragment accepts arbitrary HTML. This is by design for brainstorming flexibility. Do not expose to networks.

## Configuration

| Flag | Default | Description |
|------|---------|-------------|
| `--port` | 3333 | HTTP server port |
| `--project-dir` | `.planning/visual/` | Directory to serve and store fragments |
| `--help` | -- | Show usage information |
