← Files ConductorARCHIVED FILE

PUBLISHING.md

8.76 KB · Oct 3, 2026 · 06:32 UTC

↓ Download file

# Publishing

Maintainer-facing notes for releasing a new version of the Conductor Skills marketplace.

## Distribution channels

The plugin ships through three channels:

1. **Claude Code marketplace** — `/plugin install conductor@conductor-skills` (this repo's `.claude-plugin/marketplace.json`).
2. **install.sh / install.ps1** — `curl ... | bash` for any of the 12 supported AI agents (downloads from GitHub raw).
3. **npm** — `npm install -g @conductor-oss/conductor-skills` then `conductor-skills --agent <name>`. The npm package bundles all the same files and invokes the bundled `install.sh` / `install.ps1` with `CONDUCTOR_SKILLS_LOCAL_DIR=<package-root>` so the install scripts copy from the bundle instead of downloading.

All three channels share the same `VERSION` — bump it in one place; CI fails if any of `plugin.json`, `marketplace.json`, `package.json`, or the `VERSION` constants in the install scripts drift.

## Repo layout

```
.claude-plugin/
  plugin.json          # plugin manifest (single plugin)
  marketplace.json     # marketplace registry that lists this plugin
commands/
  conductor.md                  # /conductor menu
  conductor-setup.md            # /conductor-setup
  conductor-optimize.md         # /conductor-optimize
  conductor-scaffold-worker.md  # /conductor-scaffold-worker
skills/conductor/
  SKILL.md             # the skill itself; frontmatter `name:` must match plugin name
  references/          # lazy-loaded reference docs
  examples/            # narrative examples + raw JSON definitions
  scripts/             # bundled fallback REST script
VERSION                # source-of-truth version string
scripts/validate_plugin.py   # CI validator
.github/workflows/validate-plugin.yml
```

A user installs via:

```
/plugin marketplace add conductor-oss/conductor-skills
/plugin install conductor@conductor-skills
```

## Release checklist

1. **Pick a version** — semver. Follow the rules:
   - **Patch (1.1.0 → 1.1.1)** — wording fixes, doc-only changes, fallback script bug fixes that don't change CLI flags.
   - **Minor (1.1.0 → 1.2.0)** — new task-type docs, new examples, new reference files, additive command coverage.
   - **Major (1.1.0 → 2.0.0)** — restructured file paths users may have linked to, removed commands, breaking schema changes.

2. **Bump the version in six places** (they must agree, and CI enforces it):
   - `VERSION`
   - `.claude-plugin/plugin.json` → `version`
   - `.claude-plugin/marketplace.json` → `plugins[0].version`
   - `package.json` → `version`
   - `install.sh` → `VERSION="..."` constant near the top
   - `install.ps1` → `$SCRIPT_VERSION = "..."` constant near the top

3. **Run validation locally**:
   ```bash
   python3 scripts/validate_plugin.py
   ```
   Confirms JSON syntax, version coherence, and that each marketplace plugin entry resolves to a SKILL.md whose frontmatter name matches.

4. **Run evaluations** (if applicable):
   ```bash
   python3 scripts/run_evals.py --verbose
   ```

5. **Commit and push to `main`**. CI re-runs validation. The install scripts fetch from `main` (not from tags), so the release is live to `curl | bash` users the moment the push lands.

6. **(Optional) Tag and create a GitHub Release** for the changelog / release notes UI. The install scripts do **not** depend on tags — they read everything from `main`:
   ```bash
   git tag -a vX.Y.Z -m "Release vX.Y.Z"
   git push origin vX.Y.Z
   ```

7. **Publish to npm**:
   ```bash
   # First time only — log in with the @conductor-oss org account:
   npm login --scope=@conductor-oss

   # Sanity check what would be published:
   npm pack --dry-run

   # Publish (the package.json already has publishConfig.access = public):
   npm publish

   # Verify:
   npm view @conductor-oss/conductor-skills version
   ```

8. **Smoke-test the install** in a clean environment, hitting all three channels:
   ```bash
   # 1) Claude Code plugin path
   /plugin marketplace add conductor-oss/conductor-skills
   /plugin install conductor@conductor-skills

   # 2) install-all script (any agent)
   curl -sSL https://conductor-oss.github.io/conductor-skills/install.sh | bash -s -- --all --upgrade

   # 3) npm path
   npx @conductor-oss/conductor-skills --agent claude
   # or global:
   npm install -g @conductor-oss/conductor-skills && conductor-skills --agent cursor
   ```
   Then in a Claude Code session: `/plugin` should list `conductor` at the new version, and `conductor-skills --version` (npm path) should print the same.

## What CI validates

`scripts/validate_plugin.py`, run by `.github/workflows/validate-plugin.yml`, checks:

- `plugin.json` and `marketplace.json` parse as JSON.
- Both have required fields (`name`, `version`, `description`, `plugins`).
- `VERSION`, `plugin.json:version`, every `marketplace.json:plugins[*].version`, `package.json:version`, and the `VERSION` constants in `install.sh` and `install.ps1` all agree.
- Each marketplace plugin entry resolves to a directory containing `skills/<name>/SKILL.md`.
- Each SKILL.md has YAML frontmatter with a `name:` matching the plugin entry.
- Every file under `commands/` has YAML frontmatter with a `description:`.

It also validates that every JSON file under `skills/*/examples/workflows/` parses. Those files are loaded by users via `conductor workflow create` — broken JSON would surface only at install time, so we catch it at CI time.

## Skill evals (separate workflow)

`.github/workflows/evals.yml` runs the agent eval suite — 19 natural-language scenarios judged by an LLM. It's separate from `validate-plugin.yml` because it costs real API tokens.

### Triggers

- **`workflow_dispatch`** — run on demand. Inputs let you pick the agent model and judge model.
- **`schedule`** — Sundays 08:00 UTC against `claude-sonnet-4-6`. Weekly regression check.
- **`pull_request`** labeled `run-evals` — apply the `run-evals` label to a PR to trigger a run. Skipped on every other PR (cost control).
- **`push` to `main`** — only when files under `skills/`, `commands/`, `evaluations/`, or the eval scripts change.

### Required repository secrets

Set these under **Settings → Secrets and variables → Actions**:

| Secret | Required for | Used by |
|--------|--------------|---------|
| `ANTHROPIC_API_KEY` | All runs (default agent + default judge) | Always |
| `OPENAI_API_KEY` | Runs against `gpt-*` models | Only when model starts with `gpt-` |
| `GEMINI_API_KEY` | Runs against `gemini-*` models | Only when model starts with `gemini-` |

For PR comments on private repos, the default `GITHUB_TOKEN` is sufficient — no extra config needed.

### Outputs

Every run uploads an artifact named `eval-report-<model>` containing:
- `report.json` — machine-readable per-criterion results
- `report.html` — self-contained HTML report (open locally)

On PR runs, the workflow also posts a summary comment with totals + any failed scenarios + partial-pass deltas.

### Approximate cost per run (one model, 19 scenarios)

- Claude-Sonnet-4.6: ~$1 (agent) + ~$1 (judge) = **~$2**
- GPT-5.4: ~$2 (agent) + ~$1 (judge) = **~$3**
- Gemini-3-Flash-Preview: ~$0.20 (agent) + ~$1 (judge) = **~$1.20**

Weekly scheduled runs against the default model cost ~$2/week (~$100/year).

### Running multi-model comparisons

Two paths:

**Option A — one-click via `eval-compare.yml`.** A second workflow at `.github/workflows/eval-compare.yml` runs the suite against three models in parallel (matrix) and produces a single side-by-side HTML report. Triggers:
- `workflow_dispatch` with comma-separated `models` input
- `pull_request` labeled `run-eval-compare`

Cost: ~$6–7 per matrix run. Outputs an `eval-comparison` artifact with the combined HTML. On PR runs, posts one combined summary comment.

**Option B — manual local merge.** Run `workflow_dispatch` on `evals.yml` three times with different `model` inputs, download the three JSON artifacts, then:

```bash
python3 scripts/render_evals_html.py \
  claude-report.json gpt-report.json gemini-report.json \
  -o compare.html --title "3-model comparison"
```

## Adding a new plugin to the marketplace

1. Create `skills/<new-plugin>/SKILL.md` with frontmatter `name: <new-plugin>`.
2. Append an entry to `.claude-plugin/marketplace.json` → `plugins`:
   ```json
   {
     "name": "<new-plugin>",
     "source": "./",
     "description": "...",
     "version": "0.1.0",
     "category": "...",
     "tags": ["..."]
   }
   ```
3. Bump `VERSION` and the existing plugin's version per the rules above (or treat the new plugin's `0.1.0` as independent — see semver guidance).
4. Run `python3 scripts/validate_plugin.py` — should print `Plugin validation OK`.

> **Note:** the current setup assumes one VERSION across all plugins. If we ever publish independently versioned plugins, refactor `validate_plugin.py` to compare `marketplace.json:plugins[*].version` to a per-plugin source instead of one shared VERSION.

SHA-256: 21fba02b0936b6e2f942905bc21a2da923395886dbc9a7b9e1626d474c4693bd