# Constellation bridge

Minions ships a small read-only surface that the [Constellation](https://office.visualstudio.com/DefaultCollection/ISS/_git/constellation) dashboard polls to project Minions engine state (agents, dispatch queue, PR pipeline) into its HUD. This page documents the Minions-side of that contract.

> **The bridge polling logic itself lives in the Constellation repo** (`packages/agent/src/bridges/`). Minions only owns the on/off flag, the marker-file contract, and the `minions bridge` subcommand for local debugging.

## Quick start

```bash
minions bridge status     # Show enabled flag + last-seen Constellation agent
minions bridge health     # Probe http://127.0.0.1:7331/api/status and print the projection
minions bridge enable     # Set engine.constellationBridge.enabled = true
minions bridge disable    # Set engine.constellationBridge.enabled = false
```

## Config flag

```json
{
  "engine": {
    "constellationBridge": {
      "enabled": false
    }
  }
}
```

Default: `false`. The flag is backfilled into existing configs on `minions init` (including the implicit init that runs on every `minions update`).

**Strict semantics.** Only the literal boolean `true` enables the bridge. Any missing, malformed, or non-boolean value (e.g. the string `"true"`, the number `1`, `null`) is treated as **disabled**. The Constellation-side reader MUST mirror this check — no truthy coercion — so a typo'd `"enabled": "false"` does not silently turn the bridge on.

Toggle without editing JSON by hand:

```bash
minions bridge enable
minions bridge disable
```

Both subcommands write `~/.minions/config.json` atomically via `mutateJsonFileLocked`, so concurrent edits from the engine/dashboard cannot tear the file.

## Marker-file contract

The Constellation agent's bridge writes a marker file on every successful poll. Minions reads it with `minions bridge status` so a local operator can verify the bridge is alive and Constellation is talking to it.

- **Path:** `~/.minions/engine/constellation-bridge.json` (exposed as `CONSTELLATION_BRIDGE_MARKER_PATH` in `engine/shared.js`).
- **Owner:** the Constellation agent. The Minions engine **never** writes this file — it is a one-way breadcrumb from Constellation → Minions.

### Schema (`schemaVersion: 1`)

```json
{
  "schemaVersion": 1,
  "lastSeenAt": "2026-05-19T04:41:23.123Z",
  "agentVersion": "0.2.3",
  "source": "constellation-agent"
}
```

| Field           | Required | Notes                                                                    |
| --------------- | -------- | ------------------------------------------------------------------------ |
| `schemaVersion` | yes      | Must equal `1`. Any other value causes Minions to ignore the marker entirely (treated as no-marker, same as a missing file). New fields are added behind a deliberate version bump. |
| `lastSeenAt`    | yes      | ISO-8601 UTC timestamp of the last successful poll.                      |
| `agentVersion`  | no       | Constellation agent semver string, surfaced in `bridge status`.         |
| `source`        | no       | Free-form identifier, expected `"constellation-agent"` today.            |

Writers MUST use an atomic-replace pattern (`write to tmp + rename`) so a partial write never leaves Minions reading a half-baked JSON blob.

## `minions bridge health`

`bridge health` performs a synchronous probe of the Minions dashboard's `GET /api/status` endpoint and prints a **curated subset** — the same fields the Constellation bridge would project into its own data model. This is intentionally small: full `/api/status` is large, unstable, and may expose unrelated local state.

Sample output:

```text
bridge: dashboard reachable on http://127.0.0.1:7331
  projection (same fields the Constellation bridge would read):
    engineState: running
    enginePid: 1234
    minionsVersion: 0.1.1984
    agentCount: 5
    activeAgentCount: 2
    dispatchPending: 1
    dispatchActive: 2
    dispatchCompleted: 14
    projectCount: 3
```

If the dashboard is not listening, `bridge health` prints `dashboard not running on :7331 — start it with \`minions dash\`` and exits 1. Use this exit code to gate scripted health checks.

## Cross-repo coordination

The Constellation-side PR ([P-wi1-bridge-readonly](https://office.visualstudio.com/DefaultCollection/ISS/_git/constellation)) lands independently of this Minions PR. The Minions side merges first with the default `enabled: false`, then the Constellation side lights up bridge polling. Operators flip the flag to `true` only after both sides are deployed.

The Constellation agent's bridge reads `~/.minions/config.json` directly (no Minions HTTP API call) so config edits propagate without waiting for the engine to restart.
