Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/skills/conductor/references/execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ conductor update
The command:
1. Fetches the latest release from the GitHub Releases API
2. Compares the remote version with the locally installed version
3. If a newer version is available, runs `uv tool install --force --locked git+https://github.com/microsoft/conductor.git@v{version}` to upgrade
3. If a newer version is available, runs `uv tool install --force git+https://github.com/microsoft/conductor.git@v{version}` to upgrade
4. Clears the update-check cache on success so the next invocation re-checks cleanly

If already up to date, prints a confirmation message and exits.
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,12 @@ jobs:
ls -la dist/
uv run python -m zipfile -l dist/*.whl

- name: Generate constraints file
run: |
uv export --no-hashes --frozen --no-emit-project --no-annotate \
-o dist/constraints.txt
sha256sum dist/constraints.txt > dist/constraints.txt.sha256

- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ make validate-examples # validate all examples
- `run.py` - Workflow execution command with verbose logging helpers
- `bg_runner.py` - Background process forking for `--web-bg` mode
- `pid.py` - PID file utilities for tracking/stopping background processes
- `update.py` - Update check, version comparison, and self-upgrade via `uv tool install --locked`
- `update.py` - Update check, version comparison, and self-upgrade via `uv tool install`

- **config/**: YAML loading and Pydantic schema validation
- `schema.py` - Pydantic models for all workflow YAML structures (WorkflowConfig, AgentDef, ParallelGroup, ForEachDef, etc.)
Expand Down
32 changes: 26 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,31 @@ Conductor provides the patterns that work: evaluator-optimizer loops for iterati

## Installation

### Using uv (Recommended)
### Quick Install (Recommended)

**macOS / Linux:**
```bash
# Install from GitHub (--locked ensures reproducible dependency versions)
uv tool install --locked git+https://github.com/microsoft/conductor.git
curl -sSfL https://aka.ms/conductor/install.sh | sh
```

**Windows (PowerShell):**
```powershell
irm https://aka.ms/conductor/install.ps1 | iex
```

The installer checks for [uv](https://docs.astral.sh/uv/) (installs it if missing), fetches the latest release with pinned dependencies, and verifies integrity via SHA-256 checksum.

### Updating

```bash
conductor update
```

### Manual Install

```bash
# Install from GitHub
uv tool install git+https://github.com/microsoft/conductor.git

# Run the CLI
conductor run workflow.yaml
Expand All @@ -38,9 +58,9 @@ conductor run workflow.yaml
uvx --from git+https://github.com/microsoft/conductor.git conductor run workflow.yaml

# Install a specific branch, tag, or commit
uv tool install --locked git+https://github.com/microsoft/conductor.git@branch-name
uv tool install --locked git+https://github.com/microsoft/conductor.git@v1.0.0
uv tool install --locked git+https://github.com/microsoft/conductor.git@abc1234
uv tool install git+https://github.com/microsoft/conductor.git@branch-name
uv tool install git+https://github.com/microsoft/conductor.git@v1.0.0
uv tool install git+https://github.com/microsoft/conductor.git@abc1234
```

### Using pipx
Expand Down
123 changes: 123 additions & 0 deletions install.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# Conductor installer for Windows (PowerShell)
# Usage: irm https://aka.ms/conductor/install.ps1 | iex
#
# This script:
# 1. Checks for uv (installs it if missing)
# 2. Fetches the latest Conductor release from GitHub
# 3. Downloads and verifies the constraints file (SHA-256)
# 4. Installs Conductor via uv tool install with pinned dependencies

$ErrorActionPreference = 'Stop'

$Repo = 'microsoft/conductor'
$GitHubApi = "https://api.github.com/repos/$Repo/releases/latest"
$GitHubDL = "https://github.com/$Repo/releases/download"

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

function Write-Info { param([string]$Msg) Write-Host " → $Msg" -ForegroundColor Cyan }
function Write-Ok { param([string]$Msg) Write-Host " ✓ $Msg" -ForegroundColor Green }
function Write-Err { param([string]$Msg) Write-Host " ✗ $Msg" -ForegroundColor Red; exit 1 }

# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------

Write-Host "`nConductor Installer`n" -ForegroundColor White -NoNewline
Write-Host ""

# --- uv ---
$uvCmd = Get-Command uv -ErrorAction SilentlyContinue
if (-not $uvCmd) {
Write-Info "uv not found — installing…"
irm https://astral.sh/uv/install.ps1 | iex
# Refresh PATH so uv is available
$env:Path = [System.Environment]::GetEnvironmentVariable('Path', 'User') + ';' +
[System.Environment]::GetEnvironmentVariable('Path', 'Machine')
$uvCmd = Get-Command uv -ErrorAction SilentlyContinue
if (-not $uvCmd) {
Write-Err "uv installation succeeded but 'uv' is not on PATH. Please restart your terminal and retry."
}
Write-Ok "uv installed"
} else {
Write-Ok "uv found at $($uvCmd.Source)"
}

# --- Detect latest release ---
Write-Info "Fetching latest release…"
$headers = @{ Accept = 'application/vnd.github+json' }
$release = Invoke-RestMethod -Uri $GitHubApi -Headers $headers
$tagName = $release.tag_name

if (-not $tagName) {
Write-Err "Could not determine latest release tag from GitHub API."
}

Write-Ok "Latest release: $tagName"

# --- Check existing installation ---
$existingConductor = Get-Command conductor -ErrorAction SilentlyContinue
if ($existingConductor) {
$currentVersion = $null
try {
$versionOutput = conductor --version 2>$null
if ($versionOutput -match '(\d+\.\d+\.\d+[^ ]*)') {
$currentVersion = $Matches[1]
}
} catch { }

if ($currentVersion) {
$latestVersion = $tagName -replace '^v', ''
if ($currentVersion -eq $latestVersion) {
Write-Ok "Conductor v$currentVersion is already installed and up to date."
Write-Host ""
Write-Host " Run 'conductor --help' to get started."
Write-Host ""
exit 0
}
Write-Info "Upgrading Conductor: v$currentVersion → $tagName"
}
}

# --- Download constraints + checksum to temp directory ---
$tmpDir = Join-Path ([System.IO.Path]::GetTempPath()) "conductor-install-$([guid]::NewGuid().ToString('N').Substring(0,8))"
New-Item -ItemType Directory -Path $tmpDir -Force | Out-Null

try {
Write-Info "Downloading constraints…"
$constraintsUrl = "$GitHubDL/$tagName/constraints.txt"
$checksumUrl = "$GitHubDL/$tagName/constraints.txt.sha256"
$constraintsFile = Join-Path $tmpDir 'constraints.txt'
$checksumFile = Join-Path $tmpDir 'constraints.txt.sha256'

Invoke-WebRequest -Uri $constraintsUrl -OutFile $constraintsFile -UseBasicParsing
Invoke-WebRequest -Uri $checksumUrl -OutFile $checksumFile -UseBasicParsing

# --- Verify checksum ---
Write-Info "Verifying checksum…"
$expectedHash = (Get-Content $checksumFile -Raw).Trim().Split(' ')[0]
$actualHash = (Get-FileHash -Path $constraintsFile -Algorithm SHA256).Hash.ToLower()

if ($actualHash -ne $expectedHash) {
Write-Err "Checksum verification failed for constraints.txt (expected $expectedHash, got $actualHash)"
}
Write-Ok "Checksum verified"

# --- Install ---
Write-Info "Installing Conductor $tagName…"
uv tool install --force "git+https://github.com/$Repo.git@$tagName" -c $constraintsFile

if ($LASTEXITCODE -ne 0) {
Write-Err "uv tool install failed with exit code $LASTEXITCODE"
}

Write-Ok "Conductor $tagName installed"
Write-Host ""
Write-Host " Run 'conductor --help' to get started."
Write-Host " Run 'conductor update' to check for future updates."
Write-Host ""
} finally {
Remove-Item -Recurse -Force $tmpDir -ErrorAction SilentlyContinue
}
164 changes: 164 additions & 0 deletions install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#!/bin/sh
# Conductor installer for macOS and Linux
# Usage: curl -sSfL https://aka.ms/conductor/install.sh | sh
#
# This script:
# 1. Checks for uv (installs it if missing)
# 2. Fetches the latest Conductor release from GitHub
# 3. Downloads and verifies the constraints file (SHA-256)
# 4. Installs Conductor via uv tool install with pinned dependencies

set -eu

REPO="microsoft/conductor"
GITHUB_API="https://api.github.com/repos/${REPO}/releases/latest"
GITHUB_DL="https://github.com/${REPO}/releases/download"

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

info() {
printf ' \033[1;34m→\033[0m %s\n' "$1"
}

success() {
printf ' \033[1;32m✓\033[0m %s\n' "$1"
}

error() {
printf ' \033[1;31m✗\033[0m %s\n' "$1" >&2
exit 1
}

need_cmd() {
if ! command -v "$1" > /dev/null 2>&1; then
return 1
fi
}

# ---------------------------------------------------------------------------
# Download helper — works with curl or wget
# ---------------------------------------------------------------------------

download() {
url="$1"
dest="$2"

if need_cmd curl; then
curl -sSfL -o "$dest" "$url"
elif need_cmd wget; then
wget -qO "$dest" "$url"
else
error "Neither curl nor wget found. Please install one and retry."
fi
}

download_stdout() {
url="$1"

if need_cmd curl; then
curl -sSfL "$url"
elif need_cmd wget; then
wget -qO- "$url"
else
error "Neither curl nor wget found. Please install one and retry."
fi
}

# ---------------------------------------------------------------------------
# SHA-256 verification — works on macOS and Linux
# ---------------------------------------------------------------------------

verify_checksum() {
file="$1"
expected="$2"

if need_cmd sha256sum; then
actual=$(sha256sum "$file" | cut -d' ' -f1)
elif need_cmd shasum; then
actual=$(shasum -a 256 "$file" | cut -d' ' -f1)
else
info "Warning: cannot verify checksum (sha256sum/shasum not found), skipping"
return 0
fi

if [ "$actual" != "$expected" ]; then
error "Checksum verification failed for constraints.txt (expected ${expected}, got ${actual})"
fi
}

# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------

main() {
printf '\n\033[1mConductor Installer\033[0m\n\n'

# --- uv ---
if ! need_cmd uv; then
info "uv not found — installing…"
curl -sSfL https://astral.sh/uv/install.sh | sh
# Source the env so uv is on PATH for the rest of this script
if [ -f "$HOME/.local/bin/env" ]; then
. "$HOME/.local/bin/env"
fi
export PATH="$HOME/.local/bin:$PATH"
if ! need_cmd uv; then
error "uv installation succeeded but 'uv' is not on PATH. Please add ~/.local/bin to your PATH and retry."
fi
success "uv installed"
else
success "uv found at $(command -v uv)"
fi

# --- Detect latest release ---
info "Fetching latest release…"
release_json=$(download_stdout "$GITHUB_API")
tag_name=$(printf '%s' "$release_json" | grep -o '"tag_name"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | cut -d'"' -f4)

if [ -z "$tag_name" ]; then
error "Could not determine latest release tag from GitHub API."
fi

success "Latest release: ${tag_name}"

# --- Check existing installation ---
if need_cmd conductor; then
current_version=$(conductor --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+[^ ]*' | head -1)
if [ -n "$current_version" ]; then
latest_version=$(printf '%s' "$tag_name" | sed 's/^v//')
if [ "$current_version" = "$latest_version" ]; then
success "Conductor v${current_version} is already installed and up to date."
printf '\n Run \033[1mconductor --help\033[0m to get started.\n\n'
return 0
fi
info "Upgrading Conductor: v${current_version} → ${tag_name}"
fi
fi

# --- Download constraints + checksum ---
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT

info "Downloading constraints…"
download "${GITHUB_DL}/${tag_name}/constraints.txt" "${tmpdir}/constraints.txt"
download "${GITHUB_DL}/${tag_name}/constraints.txt.sha256" "${tmpdir}/constraints.txt.sha256"

# --- Verify checksum ---
info "Verifying checksum…"
expected_hash=$(cut -d' ' -f1 "${tmpdir}/constraints.txt.sha256")
verify_checksum "${tmpdir}/constraints.txt" "$expected_hash"
success "Checksum verified"

# --- Install ---
info "Installing Conductor ${tag_name}…"
uv tool install --force "git+https://github.com/${REPO}.git@${tag_name}" \
-c "${tmpdir}/constraints.txt"

success "Conductor ${tag_name} installed"
printf '\n Run \033[1mconductor --help\033[0m to get started.\n'
printf ' Run \033[1mconductor update\033[0m to check for future updates.\n\n'
}

main
Loading
Loading