---
name: ecosystem-health-wizard
user-invocable: false
tags: [bootstrap, ecosystem-health, wizard, config]
description: >
  Wizard prompt spec for /bootstrap --ecosystem-health. Detects CI provider
  and package manager, prompts for service endpoints, CI pipelines, and
  critical issue labels, then writes Session Config + policy file.
---

# Ecosystem-Health Wizard Spec

## Purpose

Populate the fields consumed by `skills/ecosystem-health/SKILL.md` interactively.
Without this wizard, `health-endpoints`, `cross-repos`, and CI pipeline config in
Session Config must be hand-written. This wizard detects what it can automatically,
then asks the user only for values that cannot be inferred.

**Local-only.** No network calls. The wizard reads the filesystem and writes two
files. The user reviews `git status` and commits manually.

---

## Step 1: Detection

Run silently before prompting.

```bash
node "$PLUGIN_ROOT/scripts/lib/ecosystem-wizard.mjs" --repo-root "$(pwd)" [--dry-run]
```

The detection phase reads:

| Signal | Command |
|---|---|
| CI provider | `[[ -f .gitlab-ci.yml ]] && echo gitlab` / `[[ -d .github/workflows ]] && echo github` |
| Package manager | Lockfile probe: `pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, `bun.lockb` → bun, `package-lock.json` → npm |
| Available scripts | `node -e "const p=require('./package.json'); console.log(Object.keys(p.scripts||{}).join(','))"` |

Detected values are shown to the user as context before prompting:

```
Ecosystem-Health Wizard
Detected: CI=gitlab, package-manager=pnpm
```

---

## Step 2: Prompt Sequence

Three sequential prompts. Each accepts a blank answer to skip that field.

### Prompt 2a — Health Endpoints

```
Health endpoints (format "Name|URL", comma-separated, blank to skip):
> API|https://api.example.com/health, Worker|http://worker:8080/healthz
```

- Format per entry: `<display-name>|<url>` (pipe separator).
- Comma-separated for multiple entries.
- URL must be non-empty when name is provided; malformed entries are skipped with a warning.
- Produces `health-endpoints` list in Session Config.

### Prompt 2b — CI Pipeline Identifiers

```
CI pipeline identifiers (format "id" or "id:label", comma-separated, blank to skip):
> main, deploy-production:Deploy
```

- Format per entry: `<id>` or `<id>:<display-label>`.
- For GitLab: branch name or numeric pipeline ID.
- For GitHub: workflow file name (e.g. `ci.yml`).
- Produces `pipelines` list in policy file.

### Prompt 2c — Critical Issue Labels

```
Critical issue labels (comma-separated, e.g. "priority::critical,severity:blocker", blank to skip):
> priority::critical, severity:blocker
```

- Raw label strings as they appear in the VCS issue tracker.
- Produces `criticalIssueLabels` list in policy file.

---

## Step 3: Validation

Before writing, the collected data is shape-validated using the plain-JS
validator in `scripts/lib/ecosystem-wizard.mjs` (`validateEcosystemPolicy`).

Validation rules (no Zod, no Ajv — plain JS):

- `version` must equal `1`
- `endpoints[]`: each item must have non-empty `name` and `url` strings
- `pipelines[]`: each item must have non-empty `id` string
- `criticalIssueLabels[]`: each item must be a non-empty string

When validation fails, no files are written and the errors are reported.

---

## Step 4: Output

Two files are written (or confirmed skipped if already present):

### 4a — Session Config block in CLAUDE.md (or AGENTS.md)

Appended inside the `## Session Config` section:

```yaml
ecosystem-health:
  health-endpoints:
    - name: API
      url: https://api.example.com/health
    - name: Worker
      url: http://worker:8080/healthz
  pipelines:
    - id: main
    - id: deploy-production # Deploy
  critical-issue-labels: ["priority::critical", "severity:blocker"]
```

**Idempotency:** If an `ecosystem-health:` key already exists in Session Config,
the block is NOT overwritten. The wizard prints "Skipped (already present)" and
exits 0. Re-run to edit: remove the existing block first, then re-run.

This nested `health-endpoints:` block (an indented list under a valueless header) is now parsed
content-scoped by `scripts/lib/config/health-endpoints.mjs` (#1174) — before that fix the flat
key/value reader bailed to `null` the moment it saw the `{`/nested-list shape this wizard writes,
so the block above wrote successfully but the ecosystem-health skill silently never saw it.

### 4b — `.orchestrator/policy/ecosystem.json`

```json
{
  "version": 1,
  "rationale": "Ecosystem health configuration. Generated by /bootstrap --ecosystem-health.",
  "endpoints": [
    { "name": "API", "url": "https://api.example.com/health" }
  ],
  "pipelines": [
    { "id": "main" },
    { "id": "deploy-production", "label": "Deploy" }
  ],
  "criticalIssueLabels": ["priority::critical", "severity:blocker"]
}
```

Schema: `.orchestrator/policy/ecosystem.schema.json`.

**Idempotency:** If the file already exists and the JSON contents are identical
to the proposed write, the file is skipped. If the file exists with different
contents, it is overwritten (re-run semantics).

---

## Step 5: Report

The wizard prints what it wrote and instructs the user to review before committing:

```
Ecosystem-Health Wizard complete.
Written: .orchestrator/policy/ecosystem.json, CLAUDE.md
Skipped (already present): (none)

Review changes with: git status && git diff
```

No auto-commit. The user stages and commits manually (or via the session coordinator).

---

## Idempotent Re-Run

The wizard is safe to re-run:

1. If `.orchestrator/policy/ecosystem.json` exists with identical contents → **skipped**.
2. If `ecosystem-health:` key already exists in Session Config → **skipped**.
3. If both are present and identical → both skipped, wizard exits 0 with "Nothing to do."

To update configuration: remove `ecosystem-health:` from Session Config and
delete `.orchestrator/policy/ecosystem.json`, then re-run.

---

## Error Handling

| Condition | Behaviour |
|---|---|
| `repoRoot` not provided | Exits with error: `repoRoot is required` |
| No `CLAUDE.md` or `AGENTS.md` found | Policy file is still written; Session Config skipped with warning |
| Malformed endpoint entry (missing pipe) | Entry skipped with a warning; remaining entries are processed |
| Validation failure | No files written; errors reported; exit code 1 |
| File write failure | `errors[]` entry added; partial success reported |
