Files
mims-harvard__tooluniverse/.github/workflows/release-plugin.yml
Shanghua Gao 16af425c05 Claude Code plugin: self-contained layout, skill-based routing, ML demo readiness (#161)
⏺ Introduces the Claude Code plugin for ToolUniverse as the recommended Claude Code
  integration. Replaces the previous MCP-only setup with a one-command install
  (`claude plugin install tooluniverse@tooluniverse`) that auto-configures the MCP
  server, slash commands, sub-agent, hooks, and 115 specialized research skills.

  Plugin structure
  - 115 skills routed via a single visible router (router auto-matches by question
    keywords + file extensions; sub-skills load on demand via Skill('name')).
  - 5 slash commands (research, compare, cross-validate, literature-sweep,
    translate-id) — each enforces a discipline the default agent doesn't apply.
  - 1 sub-agent (researcher) — same investigation as /tooluniverse:research but
    delegates to a forked-context subagent and returns one summary.
  - SessionStart hook (idempotent) that cleans up legacy globally-installed
    ToolUniverse skills so they don't shadow the plugin.

  Skill changes (general, not benchmark-specific)
  - Router gets a single percentage-vs-proportion units rule.
  - Sub-skills get top-of-mind discipline banners: long-format methylation
    ROWS-vs-unique-positions counting; Trimmomatic "reads completely discarded"
    = F + R + 2*D; DEG-count default reads the padj-only line; ClinVar benign-
    proportion 3-tier reporting; ortholog amino-acid single-representative sum;
    raw + log10 sensitivity for count-vs-length Pearson.

  Versions aligned at 1.2.0
  - Plugin manifest + marketplace.json + Python package (`pyproject.toml`) all at
    1.2.0. After merge, tagging v1.2.0 triggers the plugin-release workflow.

  Docs
  - New install + usage page (docs/guide/building_ai_scientists/claude_code.rst)
    covering the two-command install, version pinning, API-key setup, plugin
    troubleshooting, and the manual-MCP fallback.

  Quality measurement
  - BixBench closed-book official protocol (no reference notebook, hardened
    harness with strict leak audit and isolated workspace): 67.3% (LLM-graded).
    Compare to BixBench paper baseline 17% (Claude 3.5 Sonnet).
2026-05-21 13:12:38 -04:00

126 lines
4.4 KiB
YAML

name: Release Claude Code Plugin
#
# RELEASE CHECKLIST (maintainers — do BEFORE pushing a tag):
#
# 1. Bump version in BOTH manifest files (must match):
# - plugin/.claude-plugin/plugin.json ("version" field)
# - plugin/.claude-plugin/marketplace.json ("metadata.version")
# - .claude-plugin/marketplace.json ("metadata.version")
#
# The first one is what auto-update reads on each Claude Code startup.
# Without bumping it, users with auto-update enabled WILL NOT receive
# the new version even if you tag and release.
#
# 2. Commit + push to main. At this point, auto-update users start
# receiving the new version on next Claude Code startup.
#
# 3. Tag the commit and push the tag:
# git tag -a v1.1.12 -m "v1.1.12"
# git push origin v1.1.12
#
# The tag push triggers this workflow → builds the zip → creates a
# GitHub Release with the zip attached. The release is for offline-zip
# installs and version-pinned installs; auto-update does NOT need it.
#
# 4. Verify the release at https://github.com/mims-harvard/ToolUniverse/releases
#
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
tag:
description: 'Tag name to build (e.g., v1.1.12)'
required: true
permissions:
contents: write
jobs:
build-plugin-zip:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.tag || github.ref }}
- name: Determine tag name
id: tag
run: |
TAG="${{ github.event.inputs.tag || github.ref_name }}"
echo "name=$TAG" >> $GITHUB_OUTPUT
echo "Building plugin zip for $TAG"
- name: Build plugin artifact
run: |
set -euo pipefail
TAG="${{ steps.tag.outputs.name }}"
BUILD_DIR="build/tooluniverse-plugin-${TAG}"
mkdir -p "$BUILD_DIR"
# Copy plugin directory, resolving symlinks (skills/ uses symlinks)
cp -rL plugin/. "$BUILD_DIR/"
# Include a copy of the root marketplace manifest for optional
# "unzip and add as local marketplace" install path.
mkdir -p "$BUILD_DIR/../marketplace"
cp -r .claude-plugin "$BUILD_DIR/../marketplace/"
# Rewrite the marketplace source path to the extracted plugin dir
TAG_NAME="$TAG" python3 - <<'PY'
import json, os, pathlib
tag = os.environ["TAG_NAME"]
m = pathlib.Path("build/marketplace/.claude-plugin/marketplace.json")
data = json.loads(m.read_text())
for p in data.get("plugins", []):
if p.get("name") == "tooluniverse":
p["source"] = f"./tooluniverse-plugin-{tag}"
m.write_text(json.dumps(data, indent=2) + "\n")
PY
# Stage a top-level zip root that contains both
ZIP_ROOT="build/zip-root"
mkdir -p "$ZIP_ROOT"
mv "$BUILD_DIR" "$ZIP_ROOT/"
mv build/marketplace/.claude-plugin "$ZIP_ROOT/"
cd "$ZIP_ROOT"
zip -r "../../tooluniverse-plugin-${TAG}.zip" .
cd -
ls -la tooluniverse-plugin-${TAG}.zip
unzip -l tooluniverse-plugin-${TAG}.zip | head -30
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: tooluniverse-plugin-${{ steps.tag.outputs.name }}
path: tooluniverse-plugin-*.zip
if-no-files-found: error
- name: Attach to GitHub Release
if: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
with:
files: tooluniverse-plugin-*.zip
fail_on_unmatched_files: true
body: |
### ToolUniverse Claude Code Plugin ${{ steps.tag.outputs.name }}
Install from GitHub (recommended):
```bash
claude plugin marketplace add mims-harvard/ToolUniverse#${{ steps.tag.outputs.name }}
claude plugin install tooluniverse@tooluniverse
```
Or offline: download `tooluniverse-plugin-${{ steps.tag.outputs.name }}.zip`, unzip, then
```bash
claude plugin marketplace add ./unzipped-directory
claude plugin install tooluniverse@tooluniverse
```
Full install guide: `skills/tooluniverse-claude-code-plugin/SKILL.md`