From 3df1e8c6636ae58f36fb2b32b3eff5be1271a280 Mon Sep 17 00:00:00 2001 From: Zachary Lloyd Date: Tue, 5 May 2026 08:06:40 -0700 Subject: [PATCH 1/6] Add opt-in common skills installer Co-Authored-By: Oz --- .agents/common-skills.lock | 2 + script/bootstrap | 92 +++++++++++- script/install_common_skills | 273 +++++++++++++++++++++++++++++++++++ script/macos/bootstrap | 1 + script/run | 10 ++ script/windows/bootstrap.ps1 | 66 +++++++++ 6 files changed, 438 insertions(+), 6 deletions(-) create mode 100644 .agents/common-skills.lock create mode 100755 script/install_common_skills diff --git a/.agents/common-skills.lock b/.agents/common-skills.lock new file mode 100644 index 0000000000..0be237ec45 --- /dev/null +++ b/.agents/common-skills.lock @@ -0,0 +1,2 @@ +repo=https://github.com/warpdotdev/common-skills/ +ref=63729ade412300f8b602527a150af30a3b1235b4 diff --git a/script/bootstrap b/script/bootstrap index 59c814e416..e91e97c439 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -1,24 +1,104 @@ #!/usr/bin/env bash +set -eo pipefail # Bootstrap dispatches to the platform-specific install scripts. Each step # that needs root sources `script/warp_sudo` and asks for confirmation # before running. Pass -y / --yes (or set WARP_SKIP_SUDO_PROMPT=1) to skip # the prompts in unattended environments. +OS_TYPE="$(uname -s)" +COMMON_SKILLS_REPO_URL="${WARP_COMMON_SKILLS_REPO_URL:-https://github.com/warpdotdev/common-skills/}" +INSTALL_COMMON_SKILLS=0 +PLATFORM_ARGS=() + +usage() { + cat < + Use a specific common-skills git ref. +EOF +} + +print_bootstrap_preview() { + local platform="$1" + + echo "Warp bootstrap is starting for ${platform}." + echo "It will:" + + if [[ "${platform}" = "macOS" ]]; then + echo " - Configure Xcode as the active developer directory." + echo " - Install or update Cargo, Homebrew, PowerShell, Docker, gcloud, and related development tools." + echo " - Add the aarch64-apple-darwin Rust target." + elif [[ "${platform}" = "Linux" ]]; then + echo " - Update apt package metadata." + echo " - Install dependencies needed to build, run, and test Warp." + echo " - Install linuxdeploy and check gcloud authentication." + fi + + if [[ "${INSTALL_COMMON_SKILLS}" -eq 0 ]]; then + echo " - Skip common agent skills unless --install-common-skills is provided." + elif [[ "${WARP_SKIP_COMMON_SKILLS_INSTALL:-}" = "1" ]]; then + echo " - Skip common agent skills because WARP_SKIP_COMMON_SKILLS_INSTALL=1." + else + echo " - Install or update common agent skills from ${COMMON_SKILLS_REPO_URL} if needed." + fi + echo "Run ./script/bootstrap --help to see options and environment overrides." + echo +} + for arg in "$@"; do - case "$arg" in - -y|--yes) export WARP_SKIP_SUDO_PROMPT=1 ;; + case "${arg}" in + -h|--help) + usage + exit 0 + ;; + -y|--yes) + export WARP_SKIP_SUDO_PROMPT=1 + PLATFORM_ARGS+=("${arg}") + ;; + --install-common-skills) + INSTALL_COMMON_SKILLS=1 + ;; + *) + PLATFORM_ARGS+=("${arg}") + ;; esac done -OS_TYPE="$(uname -s)" +maybe_install_common_skills() { + if [[ "${INSTALL_COMMON_SKILLS}" -eq 1 ]]; then + ./script/install_common_skills --if-needed + fi +} if [[ "$OS_TYPE" = "Darwin" ]]; then - ./script/macos/bootstrap "$@" + print_bootstrap_preview "macOS" + ./script/macos/bootstrap "${PLATFORM_ARGS[@]}" + maybe_install_common_skills elif [[ "$OS_TYPE" = "Linux" ]]; then - ./script/linux/bootstrap "$@" + print_bootstrap_preview "Linux" + ./script/linux/bootstrap "${PLATFORM_ARGS[@]}" + maybe_install_common_skills elif [[ "$OS_TYPE" =~ ^[MINGW64_NT|MSYS_NT] ]]; then - ./script/windows/bootstrap.ps1 "$@" + if [[ "${INSTALL_COMMON_SKILLS}" -eq 1 ]]; then + ./script/windows/bootstrap.ps1 "${PLATFORM_ARGS[@]}" -InstallCommonSkills + else + ./script/windows/bootstrap.ps1 "${PLATFORM_ARGS[@]}" + fi else echo "No bootstrap script defined for the current platform!" exit 1 diff --git a/script/install_common_skills b/script/install_common_skills new file mode 100755 index 0000000000..63b0bcda5c --- /dev/null +++ b/script/install_common_skills @@ -0,0 +1,273 @@ +#!/usr/bin/env bash + +set -eo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd)" +LOCK_FILE="${REPO_ROOT}/.agents/common-skills.lock" +STAMP_FILENAME=".common-skills-install.json" + +IF_NEEDED=0 +NON_INTERACTIVE=0 +FORCE=0 +QUIET=0 +DEST_DIR="${WARP_COMMON_SKILLS_DEST_DIR:-}" + +usage() { + cat < + Override the git ref from .agents/common-skills.lock. +EOF +} + +log() { + if [[ "${QUIET}" -ne 1 ]]; then + echo "$@" + fi +} + +lock_value() { + local key="$1" + sed -n "s/^${key}=//p" "${LOCK_FILE}" | tail -n 1 +} + +stamp_path_for_dest() { + local dest_dir="$1" + echo "${dest_dir}/.agents/skills/${STAMP_FILENAME}" +} + +stamp_value() { + local stamp_file="$1" + local key="$2" + + if [[ ! -f "${stamp_file}" ]]; then + return + fi + + sed -n "s/.*\"${key}\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" "${stamp_file}" | tail -n 1 +} + +repo_root() { + git -C "${REPO_ROOT}" rev-parse --show-toplevel 2>/dev/null || echo "${REPO_ROOT}" +} + +choose_dest_dir() { + local home_dir="${HOME}" + local repo_dir="$(repo_root)" + local response="" + + if [[ -n "${DEST_DIR}" ]]; then + echo "${DEST_DIR}" + return + fi + + if [[ "${NON_INTERACTIVE}" -eq 1 ]]; then + if [[ -f "$(stamp_path_for_dest "${home_dir}")" ]]; then + echo "${home_dir}" + return + fi + + if [[ -f "$(stamp_path_for_dest "${repo_dir}")" ]]; then + echo "${repo_dir}" + return + fi + + echo "" + return + fi + + if [[ ! -t 0 ]]; then + echo "" + return + fi + + echo "Install common agent skills from warpdotdev/common-skills:" >&2 + echo " 1) ${home_dir}/.agents/skills (recommended for Warp team members)" >&2 + echo " 2) ${repo_dir}/.agents/skills (recommended for OpenWarp contributors)" >&2 + + while true; do + read -r -p "Choose an install location [1/2]: " response + case "${response}" in + 1) + echo "${home_dir}" + return + ;; + 2) + echo "${repo_dir}" + return + ;; + *) + echo "Please choose 1 or 2." >&2 + ;; + esac + done +} + +prepare_common_skills_source() { + local repo_url="$1" + local ref="$2" + local source_dir="$3" + + if [[ -d "${repo_url}" ]]; then + echo "${repo_url}" + return + fi + + git clone "${repo_url}" "${source_dir}" + git -C "${source_dir}" checkout --quiet "${ref}" + echo "${source_dir}" +} + +actual_source_ref() { + local source_dir="$1" + git -C "${source_dir}" rev-parse HEAD +} + +remove_existing_common_skill_dirs() { + local source_dir="$1" + local dest_dir="$2" + local source_skills_dir="${source_dir}/.agents/skills" + local dest_skills_dir="${dest_dir}/.agents/skills" + local skill_dir="" + + if [[ ! -d "${source_skills_dir}" ]]; then + echo "error: common-skills source does not contain ${source_skills_dir}" >&2 + return 1 + fi + + while IFS= read -r skill_dir; do + rm -rf "${dest_skills_dir}/$(basename "${skill_dir}")" + done < <(find "${source_skills_dir}" -mindepth 1 -maxdepth 1 -type d | sort) +} + +write_stamp() { + local dest_dir="$1" + local repo_url="$2" + local ref="$3" + local stamp_file="$(stamp_path_for_dest "${dest_dir}")" + local installed_at="" + + installed_at="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" + mkdir -p "$(dirname "${stamp_file}")" + cat > "${stamp_file}" <&2 + exit 1 + fi + DEST_DIR="$2" + shift 2 + ;; + --quiet) + QUIET=1 + shift + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "error: unknown argument: $1" >&2 + usage >&2 + exit 1 + ;; + esac +done + +if [[ "${WARP_SKIP_COMMON_SKILLS_INSTALL:-}" = "1" ]]; then + log "Skipping common-skills install because WARP_SKIP_COMMON_SKILLS_INSTALL=1." + exit 0 +fi + +if [[ ! -f "${LOCK_FILE}" ]]; then + echo "error: missing common-skills lock file: ${LOCK_FILE}" >&2 + exit 1 +fi + +LOCK_REPO="$(lock_value repo)" +LOCK_REF="$(lock_value ref)" +COMMON_SKILLS_REPO_URL="${WARP_COMMON_SKILLS_REPO_URL:-${LOCK_REPO}}" +COMMON_SKILLS_REF="${WARP_COMMON_SKILLS_REF:-${LOCK_REF}}" + +if [[ -z "${COMMON_SKILLS_REPO_URL}" || -z "${COMMON_SKILLS_REF}" ]]; then + echo "error: ${LOCK_FILE} must define repo= and ref=" >&2 + exit 1 +fi + +DEST_DIR="$(choose_dest_dir)" + +if [[ -z "${DEST_DIR}" ]]; then + log "Common skills are not installed yet; run ./script/bootstrap once or set WARP_COMMON_SKILLS_DEST_DIR." + exit 0 +fi + +if [[ -d "${COMMON_SKILLS_REPO_URL}" && -z "${WARP_COMMON_SKILLS_REF:-}" ]]; then + COMMON_SKILLS_REF="$(git -C "${COMMON_SKILLS_REPO_URL}" rev-parse HEAD)" +fi + +STAMP_FILE="$(stamp_path_for_dest "${DEST_DIR}")" +STAMP_REPO="$(stamp_value "${STAMP_FILE}" repo)" +STAMP_REF="$(stamp_value "${STAMP_FILE}" ref)" + +if [[ "${FORCE}" -ne 1 && "${IF_NEEDED}" -eq 1 && "${STAMP_REPO}" = "${COMMON_SKILLS_REPO_URL}" && "${STAMP_REF}" = "${COMMON_SKILLS_REF}" ]]; then + log "Common skills are already up to date." + exit 0 +fi + +SOURCE_CLONE_DIR="$(mktemp -d "${TMPDIR:-/tmp}/common-skills-source.XXXXXX")" +SKILLS_CLONE_DIR="$(mktemp -d "${TMPDIR:-/tmp}/common-skills.XXXXXX")" + +cleanup() { + rm -rf "${SOURCE_CLONE_DIR}" "${SKILLS_CLONE_DIR}" +} +trap cleanup EXIT + +SOURCE_DIR="$(prepare_common_skills_source "${COMMON_SKILLS_REPO_URL}" "${COMMON_SKILLS_REF}" "${SOURCE_CLONE_DIR}")" +ACTUAL_REF="$(actual_source_ref "${SOURCE_DIR}")" + +echo "Installing common agent skills from ${COMMON_SKILLS_REPO_URL} at ${ACTUAL_REF}." +remove_existing_common_skill_dirs "${SOURCE_DIR}" "${DEST_DIR}" +WARP_COMMON_SKILLS_REPO_URL="${SOURCE_DIR}" \ + bash "${SOURCE_DIR}/scripts/install.sh" --clone-dir "${SKILLS_CLONE_DIR}" --dest-dir "${DEST_DIR}" +write_stamp "${DEST_DIR}" "${COMMON_SKILLS_REPO_URL}" "${ACTUAL_REF}" diff --git a/script/macos/bootstrap b/script/macos/bootstrap index 12317f6022..77734fd687 100755 --- a/script/macos/bootstrap +++ b/script/macos/bootstrap @@ -11,6 +11,7 @@ if ! [ -d "/Applications/Xcode.app" ]; then echo "Please install Xcode from the App Store before continuing." exit 1 fi +echo "You may be prompted for your password so bootstrap can set Xcode as the active developer directory." warp_sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer # Mimic actually launching XCode, which performs some necessary set-up of the diff --git a/script/run b/script/run index 25f1925bf5..59b578e113 100755 --- a/script/run +++ b/script/run @@ -19,6 +19,7 @@ cd "${REPO_ROOT}" OS_TYPE="$(uname -s)" FEATURES="gui" +INSTALL_COMMON_SKILLS=0 ./script/install_channel_config || echo "Skipping internal channel config installation (no repo access)." @@ -63,6 +64,10 @@ while (( "$#" )); do exit 1 fi ;; + --install-common-skills) + INSTALL_COMMON_SKILLS=1 + shift + ;; --release) CARGO_PARAMS+=("$1") MAC_ARGS+=("$1") @@ -87,6 +92,11 @@ while (( "$#" )); do esac done +if [[ "$INSTALL_COMMON_SKILLS" -eq 1 ]]; then + echo "Checking common agent skills version..." + ./script/install_common_skills --if-needed --non-interactive --quiet || echo "Skipping common-skills update." +fi + # These cargo features were removed and replaced by environment variables read # by warp-channel-config. Intercept them here so that existing --features # invocations keep working. diff --git a/script/windows/bootstrap.ps1 b/script/windows/bootstrap.ps1 index 71109641d7..e9e1638e65 100644 --- a/script/windows/bootstrap.ps1 +++ b/script/windows/bootstrap.ps1 @@ -1,7 +1,64 @@ #!/usr/bin/env powershell +param( + [switch]$Help, + [switch]$InstallCommonSkills +) $ErrorActionPreference = 'Stop' +if ([string]::IsNullOrWhiteSpace($env:WARP_COMMON_SKILLS_REPO_URL)) { + $commonSkillsRepoUrl = 'https://github.com/warpdotdev/common-skills/' +} else { + $commonSkillsRepoUrl = $env:WARP_COMMON_SKILLS_REPO_URL +} + +function Show-Usage { + Write-Output 'Usage: .\script\windows\bootstrap.ps1 [-Help] [-InstallCommonSkills]' + Write-Output '' + Write-Output 'Prepare this checkout for Warp development on Windows.' + Write-Output '' + Write-Output 'Options:' + Write-Output ' -Help Show this help message.' + Write-Output ' -InstallCommonSkills Install or update common agent skills from warpdotdev/common-skills.' + Write-Output '' + Write-Output 'Environment:' + Write-Output ' WARP_SKIP_COMMON_SKILLS_INSTALL=1' + Write-Output ' Skip installing common agent skills.' + Write-Output ' WARP_COMMON_SKILLS_DEST_DIR=C:\path\to\base-dir' + Write-Output ' Install common skills into C:\path\to\base-dir\.agents\skills without prompting.' + Write-Output ' WARP_COMMON_SKILLS_REPO_URL=C:\path\to\common-skills-or-git-url' + Write-Output ' Use a specific common-skills checkout or repository URL.' + Write-Output ' WARP_COMMON_SKILLS_REF=' + Write-Output ' Use a specific common-skills git ref.' +} + +function Show-BootstrapPreview { + Write-Output 'Warp bootstrap is starting for Windows.' + Write-Output 'It will:' + Write-Output ' - Check for Git for Windows.' + Write-Output ' - Install Rust if cargo is unavailable.' + Write-Output ' - Install Visual Studio Build Tools, jq, CMake, InnoSetup, and gcloud as needed.' + Write-Output ' - Install Cargo test dependencies.' + + if (-not $InstallCommonSkills) { + Write-Output ' - Skip common agent skills unless -InstallCommonSkills is provided.' + } elseif ($env:WARP_SKIP_COMMON_SKILLS_INSTALL -eq '1') { + Write-Output ' - Skip common agent skills because WARP_SKIP_COMMON_SKILLS_INSTALL=1.' + } else { + Write-Output " - Install or update common agent skills from $commonSkillsRepoUrl if needed." + } + + Write-Output 'Run .\script\windows\bootstrap.ps1 -Help to see options and environment overrides.' + Write-Output '' +} + +if ($Help) { + Show-Usage + exit 0 +} + +Show-BootstrapPreview + # Git for Windows can be installed system-wide (Program Files) or per-user (LOCALAPPDATA\Programs\Git). $gitBinCandidates = @( "$env:PROGRAMFILES\Git\bin", @@ -13,6 +70,11 @@ if (-not $gitBinDir) { Write-Error 'https://gitforwindows.org/' exit 1 } +$env:PATH = "$gitBinDir;$env:PATH" + +function Install-CommonSkills { + & "$gitBinDir\bash.exe" "$PWD\script\install_common_skills" --if-needed +} if (-not (Get-Command -Name cargo -Type Application -ErrorAction SilentlyContinue)) { Write-Output 'Installing rust...' @@ -69,3 +131,7 @@ if ($identityToken.Trim().Length -eq 0) { Read-Host gcloud auth login } + +if ($InstallCommonSkills) { + Install-CommonSkills +} From 6501e30a1e72d0ec816f90dfc3705554881fbf6e Mon Sep 17 00:00:00 2001 From: Zachary Lloyd Date: Tue, 5 May 2026 16:53:57 -0700 Subject: [PATCH 2/6] Honor explicit common skills refs for local sources Co-Authored-By: Oz --- script/install_common_skills | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/script/install_common_skills b/script/install_common_skills index 63b0bcda5c..74c41f13e6 100755 --- a/script/install_common_skills +++ b/script/install_common_skills @@ -127,6 +127,12 @@ prepare_common_skills_source() { local source_dir="$3" if [[ -d "${repo_url}" ]]; then + if [[ -n "${WARP_COMMON_SKILLS_REF:-}" ]]; then + git clone "${repo_url}" "${source_dir}" + git -C "${source_dir}" checkout --quiet "${ref}" + echo "${source_dir}" + return + fi echo "${repo_url}" return fi From 6c7a5aeb27de29b29dbb7231ccfacccf70a340d1 Mon Sep 17 00:00:00 2001 From: Zachary Lloyd Date: Wed, 6 May 2026 11:33:15 -0700 Subject: [PATCH 3/6] Use npx skills CLI for common skills install Co-Authored-By: Oz --- .agents/common-skills.lock | 2 +- script/install_common_skills | 21 +++++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/.agents/common-skills.lock b/.agents/common-skills.lock index 0be237ec45..ad69d56e93 100644 --- a/.agents/common-skills.lock +++ b/.agents/common-skills.lock @@ -1,2 +1,2 @@ repo=https://github.com/warpdotdev/common-skills/ -ref=63729ade412300f8b602527a150af30a3b1235b4 +ref=12d2e2b787d7af4ef1b4455949b864fc5637dcff diff --git a/script/install_common_skills b/script/install_common_skills index 74c41f13e6..74aee1c1dd 100755 --- a/script/install_common_skills +++ b/script/install_common_skills @@ -163,6 +163,21 @@ remove_existing_common_skill_dirs() { rm -rf "${dest_skills_dir}/$(basename "${skill_dir}")" done < <(find "${source_skills_dir}" -mindepth 1 -maxdepth 1 -type d | sort) } +install_common_skills_from_source() { + local source_dir="$1" + local dest_dir="$2" + + if [[ "${dest_dir}" = "${HOME}" ]]; then + HOME="${dest_dir}" npx --yes skills@latest add "${source_dir}" --skill '*' --agent warp --copy --global -y + return + fi + + mkdir -p "${dest_dir}" + ( + cd "${dest_dir}" + npx --yes skills@latest add "${source_dir}" --skill '*' --agent warp --copy -y + ) +} write_stamp() { local dest_dir="$1" @@ -262,10 +277,9 @@ if [[ "${FORCE}" -ne 1 && "${IF_NEEDED}" -eq 1 && "${STAMP_REPO}" = "${COMMON_SK fi SOURCE_CLONE_DIR="$(mktemp -d "${TMPDIR:-/tmp}/common-skills-source.XXXXXX")" -SKILLS_CLONE_DIR="$(mktemp -d "${TMPDIR:-/tmp}/common-skills.XXXXXX")" cleanup() { - rm -rf "${SOURCE_CLONE_DIR}" "${SKILLS_CLONE_DIR}" + rm -rf "${SOURCE_CLONE_DIR}" } trap cleanup EXIT @@ -274,6 +288,5 @@ ACTUAL_REF="$(actual_source_ref "${SOURCE_DIR}")" echo "Installing common agent skills from ${COMMON_SKILLS_REPO_URL} at ${ACTUAL_REF}." remove_existing_common_skill_dirs "${SOURCE_DIR}" "${DEST_DIR}" -WARP_COMMON_SKILLS_REPO_URL="${SOURCE_DIR}" \ - bash "${SOURCE_DIR}/scripts/install.sh" --clone-dir "${SKILLS_CLONE_DIR}" --dest-dir "${DEST_DIR}" +install_common_skills_from_source "${SOURCE_DIR}" "${DEST_DIR}" write_stamp "${DEST_DIR}" "${COMMON_SKILLS_REPO_URL}" "${ACTUAL_REF}" From 3fa4491c3975b144145e7aa7cd1e92b9799d7de7 Mon Sep 17 00:00:00 2001 From: Zachary Lloyd Date: Wed, 6 May 2026 11:46:43 -0700 Subject: [PATCH 4/6] Fix PowerShell lint for common skills bootstrap Co-Authored-By: Oz --- script/windows/bootstrap.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/script/windows/bootstrap.ps1 b/script/windows/bootstrap.ps1 index e9e1638e65..0ec2ff5864 100644 --- a/script/windows/bootstrap.ps1 +++ b/script/windows/bootstrap.ps1 @@ -72,7 +72,7 @@ if (-not $gitBinDir) { } $env:PATH = "$gitBinDir;$env:PATH" -function Install-CommonSkills { +function Install-CommonSkill { & "$gitBinDir\bash.exe" "$PWD\script\install_common_skills" --if-needed } @@ -133,5 +133,5 @@ if ($identityToken.Trim().Length -eq 0) { } if ($InstallCommonSkills) { - Install-CommonSkills + Install-CommonSkill } From 84b8b6d40de7a8df5e3bf44ed2d832f27f12a007 Mon Sep 17 00:00:00 2001 From: Zachary Lloyd Date: Sat, 9 May 2026 11:53:09 -0600 Subject: [PATCH 5/6] Use standard skills lock for common skills Replace the custom common-skills lock with the project skills-lock.json managed by npx skills. Restore checked-in skills through script/run and bootstrap using the standard lock, and document the local and Oz cloud environment flows in a tech spec. Co-Authored-By: Oz --- .agents/common-skills.lock | 2 - .agents/skills/create-pr/SKILL.md | 3 +- .agents/skills/implement-specs/SKILL.md | 3 +- .../spec-driven-implementation/SKILL.md | 2 +- .agents/skills/update-skill/SKILL.md | 3 +- WARP.md | 4 + script/bootstrap | 11 +- script/install_common_skills | 233 +++--------------- script/run | 12 +- script/windows/bootstrap.ps1 | 16 +- skills-lock.json | 65 +++++ specs/common-skills-installation/TECH.md | 87 +++++++ 12 files changed, 206 insertions(+), 235 deletions(-) delete mode 100644 .agents/common-skills.lock create mode 100644 skills-lock.json create mode 100644 specs/common-skills-installation/TECH.md diff --git a/.agents/common-skills.lock b/.agents/common-skills.lock deleted file mode 100644 index ad69d56e93..0000000000 --- a/.agents/common-skills.lock +++ /dev/null @@ -1,2 +0,0 @@ -repo=https://github.com/warpdotdev/common-skills/ -ref=12d2e2b787d7af4ef1b4455949b864fc5637dcff diff --git a/.agents/skills/create-pr/SKILL.md b/.agents/skills/create-pr/SKILL.md index 01f1b4fae5..032d3bf41d 100644 --- a/.agents/skills/create-pr/SKILL.md +++ b/.agents/skills/create-pr/SKILL.md @@ -12,7 +12,6 @@ This guide covers best practices for creating pull requests in the warp reposito ## Related Skills - `fix-errors` - Fix presubmit failures (formatting, linting, tests) before opening PR -- `rust-unit-tests` - Write unit tests for your changes, if applicable (see "Testing Requirements" below) - `warp-integration-test` - Add or update integration coverage for user-visible flows, regressions, and P0 use cases - `add-feature-flag` - Gate changes behind feature flags @@ -156,7 +155,7 @@ Code with non-trivial logic should have unit tests to validate functionality: - Sufficiently-simple functions - Trivial getters/setters -See the `rust-unit-tests` skill for guidance on writing unit tests. +Follow the repository's local testing conventions for guidance on writing unit tests. ### UI components need layout validation tests diff --git a/.agents/skills/implement-specs/SKILL.md b/.agents/skills/implement-specs/SKILL.md index d30b84c955..459339bebb 100644 --- a/.agents/skills/implement-specs/SKILL.md +++ b/.agents/skills/implement-specs/SKILL.md @@ -73,7 +73,7 @@ Before considering the work complete, verify that the code matches the current s Prefer: -- `rust-unit-tests` for unit tests and regression coverage +- unit tests and regression coverage that follow the repository's local testing conventions - integration or end-to-end tests for important user flows ## Best Practices @@ -88,4 +88,3 @@ Prefer: - `spec-driven-implementation` - `write-product-spec` - `write-tech-spec` -- `rust-unit-tests` diff --git a/.agents/skills/spec-driven-implementation/SKILL.md b/.agents/skills/spec-driven-implementation/SKILL.md index 3214ca47dc..73c8dc054b 100644 --- a/.agents/skills/spec-driven-implementation/SKILL.md +++ b/.agents/skills/spec-driven-implementation/SKILL.md @@ -122,7 +122,7 @@ The checked-in specs should describe the feature that actually ships, not just t Before considering the work complete, make sure verification maps back to the specs. Prefer tests and artifacts that validate the product behavior directly: -- use the `rust-unit-tests` skill for crate-level unit tests and regression coverage +- unit tests and regression coverage that follow the repository's local testing conventions - integration tests for critical user flows - loom walkthroughs or equivalent feature demonstrations when appropriate - screenshots or videos when useful for UI-heavy work diff --git a/.agents/skills/update-skill/SKILL.md b/.agents/skills/update-skill/SKILL.md index a17cd9e2d8..b301684896 100644 --- a/.agents/skills/update-skill/SKILL.md +++ b/.agents/skills/update-skill/SKILL.md @@ -36,7 +36,7 @@ Use this skill when the user needs to work with PDF files... Every SKILL.md must start with YAML frontmatter containing: - **name**: Kebab-case identifier (lowercase letters, numbers, hyphens only) - - Example: `add-feature-flag`, `rust-unit-tests`, `update-skill` + - Example: `add-feature-flag`, `pdf-processing`, `update-skill` - **description**: Specific description of what the skill does and when to use it - Must be non-empty - Should include key terms for skill discovery @@ -101,7 +101,6 @@ Keep only essential workflow and procedural instructions in SKILL.md. Move detai For reference on structure and style: - `.agents/skills/add-feature-flag/SKILL.md` - Multi-step workflow with clear sequential steps -- `.agents/skills/rust-unit-tests/SKILL.md` - Comprehensive guide with code examples and helper utilities - `.agents/skills/remove-feature-flag/SKILL.md` - Cleanup workflow with search commands ## Best Practices diff --git a/WARP.md b/WARP.md index 9b9fec9f6a..6a9f5de0b7 100644 --- a/WARP.md +++ b/WARP.md @@ -38,9 +38,13 @@ Environment variables: ### Platform Setup - `./script/bootstrap` - Platform-specific setup (calls platform-specific bootstrap scripts) +- `./script/bootstrap --install-common-skills` - Platform setup plus common agent skill installation from `skills-lock.json`. +- `./script/install_common_skills --if-needed` - Install or refresh shared agent skills from the standard `npx skills` project lock. - `./script/install_cargo_build_deps` - Install Cargo build dependencies - `./script/install_cargo_test_deps` - Install Cargo test dependencies +`skills-lock.json` is the standard project lock file managed by `npx skills`. `script/run` checks this lock before building and restores the checked-in project skills with `npx skills experimental_install` when the local install stamp is stale. To update the locked common skills, run `npx --yes skills@latest update -p -y` and commit the resulting `skills-lock.json` and `.agents/skills` changes. + ## Architecture Overview This is a Rust-based terminal emulator with a custom UI framework called **WarpUI**. diff --git a/script/bootstrap b/script/bootstrap index e91e97c439..8ef43bd941 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -7,7 +7,6 @@ set -eo pipefail # the prompts in unattended environments. OS_TYPE="$(uname -s)" -COMMON_SKILLS_REPO_URL="${WARP_COMMON_SKILLS_REPO_URL:-https://github.com/warpdotdev/common-skills/}" INSTALL_COMMON_SKILLS=0 PLATFORM_ARGS=() @@ -19,17 +18,11 @@ Prepare this checkout for Warp development by running the platform-specific boot Options: -h, --help Show this help message. - --install-common-skills Install or update common agent skills from warpdotdev/common-skills. + --install-common-skills Install or update common agent skills from skills-lock.json. Environment: WARP_SKIP_COMMON_SKILLS_INSTALL=1 Skip installing common agent skills, even when --install-common-skills is provided. - WARP_COMMON_SKILLS_DEST_DIR=/path/to/base-dir - Install common skills into /path/to/base-dir/.agents/skills without prompting. - WARP_COMMON_SKILLS_REPO_URL=/path/to/common-skills-or-git-url - Use a specific common-skills checkout or repository URL. - WARP_COMMON_SKILLS_REF= - Use a specific common-skills git ref. EOF } @@ -54,7 +47,7 @@ print_bootstrap_preview() { elif [[ "${WARP_SKIP_COMMON_SKILLS_INSTALL:-}" = "1" ]]; then echo " - Skip common agent skills because WARP_SKIP_COMMON_SKILLS_INSTALL=1." else - echo " - Install or update common agent skills from ${COMMON_SKILLS_REPO_URL} if needed." + echo " - Install or update common agent skills from skills-lock.json if needed." fi echo "Run ./script/bootstrap --help to see options and environment overrides." echo diff --git a/script/install_common_skills b/script/install_common_skills index 74aee1c1dd..0c690ac4df 100755 --- a/script/install_common_skills +++ b/script/install_common_skills @@ -3,38 +3,29 @@ set -eo pipefail REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd)" -LOCK_FILE="${REPO_ROOT}/.agents/common-skills.lock" -STAMP_FILENAME=".common-skills-install.json" +LOCK_FILE="${REPO_ROOT}/skills-lock.json" +STAMP_RELATIVE_PATH="warp/common-skills-lock.hash" IF_NEEDED=0 -NON_INTERACTIVE=0 FORCE=0 QUIET=0 -DEST_DIR="${WARP_COMMON_SKILLS_DEST_DIR:-}" usage() { cat < - Override the git ref from .agents/common-skills.lock. EOF } @@ -44,160 +35,43 @@ log() { fi } -lock_value() { - local key="$1" - sed -n "s/^${key}=//p" "${LOCK_FILE}" | tail -n 1 +lock_hash() { + git -C "${REPO_ROOT}" hash-object "${LOCK_FILE}" } -stamp_path_for_dest() { - local dest_dir="$1" - echo "${dest_dir}/.agents/skills/${STAMP_FILENAME}" -} - -stamp_value() { - local stamp_file="$1" - local key="$2" - - if [[ ! -f "${stamp_file}" ]]; then - return - fi - - sed -n "s/.*\"${key}\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" "${stamp_file}" | tail -n 1 -} - -repo_root() { - git -C "${REPO_ROOT}" rev-parse --show-toplevel 2>/dev/null || echo "${REPO_ROOT}" -} - -choose_dest_dir() { - local home_dir="${HOME}" - local repo_dir="$(repo_root)" - local response="" - - if [[ -n "${DEST_DIR}" ]]; then - echo "${DEST_DIR}" - return - fi +stamp_file() { + local git_path="" - if [[ "${NON_INTERACTIVE}" -eq 1 ]]; then - if [[ -f "$(stamp_path_for_dest "${home_dir}")" ]]; then - echo "${home_dir}" - return - fi - - if [[ -f "$(stamp_path_for_dest "${repo_dir}")" ]]; then - echo "${repo_dir}" - return - fi - - echo "" - return - fi - - if [[ ! -t 0 ]]; then - echo "" - return - fi - - echo "Install common agent skills from warpdotdev/common-skills:" >&2 - echo " 1) ${home_dir}/.agents/skills (recommended for Warp team members)" >&2 - echo " 2) ${repo_dir}/.agents/skills (recommended for OpenWarp contributors)" >&2 - - while true; do - read -r -p "Choose an install location [1/2]: " response - case "${response}" in - 1) - echo "${home_dir}" - return - ;; - 2) - echo "${repo_dir}" - return + if git_path="$(git -C "${REPO_ROOT}" rev-parse --git-path "${STAMP_RELATIVE_PATH}" 2>/dev/null)"; then + case "${git_path}" in + /*) + echo "${git_path}" ;; *) - echo "Please choose 1 or 2." >&2 + echo "${REPO_ROOT}/${git_path}" ;; esac - done -} - -prepare_common_skills_source() { - local repo_url="$1" - local ref="$2" - local source_dir="$3" - - if [[ -d "${repo_url}" ]]; then - if [[ -n "${WARP_COMMON_SKILLS_REF:-}" ]]; then - git clone "${repo_url}" "${source_dir}" - git -C "${source_dir}" checkout --quiet "${ref}" - echo "${source_dir}" - return - fi - echo "${repo_url}" return fi - git clone "${repo_url}" "${source_dir}" - git -C "${source_dir}" checkout --quiet "${ref}" - echo "${source_dir}" + echo "${REPO_ROOT}/.agents/skills/.common-skills-lock.hash" } -actual_source_ref() { - local source_dir="$1" - git -C "${source_dir}" rev-parse HEAD -} - -remove_existing_common_skill_dirs() { - local source_dir="$1" - local dest_dir="$2" - local source_skills_dir="${source_dir}/.agents/skills" - local dest_skills_dir="${dest_dir}/.agents/skills" - local skill_dir="" +stamp_hash() { + local file="$1" - if [[ ! -d "${source_skills_dir}" ]]; then - echo "error: common-skills source does not contain ${source_skills_dir}" >&2 - return 1 + if [[ -f "${file}" ]]; then + cat "${file}" fi - - while IFS= read -r skill_dir; do - rm -rf "${dest_skills_dir}/$(basename "${skill_dir}")" - done < <(find "${source_skills_dir}" -mindepth 1 -maxdepth 1 -type d | sort) } -install_common_skills_from_source() { - local source_dir="$1" - local dest_dir="$2" - if [[ "${dest_dir}" = "${HOME}" ]]; then - HOME="${dest_dir}" npx --yes skills@latest add "${source_dir}" --skill '*' --agent warp --copy --global -y - return - fi - - mkdir -p "${dest_dir}" +install_from_lock() { ( - cd "${dest_dir}" - npx --yes skills@latest add "${source_dir}" --skill '*' --agent warp --copy -y + cd "${REPO_ROOT}" + npx --yes skills@latest experimental_install ) } -write_stamp() { - local dest_dir="$1" - local repo_url="$2" - local ref="$3" - local stamp_file="$(stamp_path_for_dest "${dest_dir}")" - local installed_at="" - - installed_at="$(date -u +"%Y-%m-%dT%H:%M:%SZ")" - mkdir -p "$(dirname "${stamp_file}")" - cat > "${stamp_file}" <&2 - exit 1 - fi - DEST_DIR="$2" - shift 2 - ;; --quiet) QUIET=1 shift @@ -242,51 +107,21 @@ if [[ "${WARP_SKIP_COMMON_SKILLS_INSTALL:-}" = "1" ]]; then fi if [[ ! -f "${LOCK_FILE}" ]]; then - echo "error: missing common-skills lock file: ${LOCK_FILE}" >&2 - exit 1 -fi - -LOCK_REPO="$(lock_value repo)" -LOCK_REF="$(lock_value ref)" -COMMON_SKILLS_REPO_URL="${WARP_COMMON_SKILLS_REPO_URL:-${LOCK_REPO}}" -COMMON_SKILLS_REF="${WARP_COMMON_SKILLS_REF:-${LOCK_REF}}" - -if [[ -z "${COMMON_SKILLS_REPO_URL}" || -z "${COMMON_SKILLS_REF}" ]]; then - echo "error: ${LOCK_FILE} must define repo= and ref=" >&2 + echo "error: missing skills lock file: ${LOCK_FILE}" >&2 exit 1 fi -DEST_DIR="$(choose_dest_dir)" +LOCK_HASH="$(lock_hash)" +STAMP_FILE="$(stamp_file)" +STAMP_HASH="$(stamp_hash "${STAMP_FILE}")" -if [[ -z "${DEST_DIR}" ]]; then - log "Common skills are not installed yet; run ./script/bootstrap once or set WARP_COMMON_SKILLS_DEST_DIR." - exit 0 -fi - -if [[ -d "${COMMON_SKILLS_REPO_URL}" && -z "${WARP_COMMON_SKILLS_REF:-}" ]]; then - COMMON_SKILLS_REF="$(git -C "${COMMON_SKILLS_REPO_URL}" rev-parse HEAD)" -fi - -STAMP_FILE="$(stamp_path_for_dest "${DEST_DIR}")" -STAMP_REPO="$(stamp_value "${STAMP_FILE}" repo)" -STAMP_REF="$(stamp_value "${STAMP_FILE}" ref)" - -if [[ "${FORCE}" -ne 1 && "${IF_NEEDED}" -eq 1 && "${STAMP_REPO}" = "${COMMON_SKILLS_REPO_URL}" && "${STAMP_REF}" = "${COMMON_SKILLS_REF}" ]]; then +if [[ "${FORCE}" -ne 1 && "${IF_NEEDED}" -eq 1 && "${STAMP_HASH}" = "${LOCK_HASH}" ]]; then log "Common skills are already up to date." exit 0 fi -SOURCE_CLONE_DIR="$(mktemp -d "${TMPDIR:-/tmp}/common-skills-source.XXXXXX")" - -cleanup() { - rm -rf "${SOURCE_CLONE_DIR}" -} -trap cleanup EXIT - -SOURCE_DIR="$(prepare_common_skills_source "${COMMON_SKILLS_REPO_URL}" "${COMMON_SKILLS_REF}" "${SOURCE_CLONE_DIR}")" -ACTUAL_REF="$(actual_source_ref "${SOURCE_DIR}")" - -echo "Installing common agent skills from ${COMMON_SKILLS_REPO_URL} at ${ACTUAL_REF}." -remove_existing_common_skill_dirs "${SOURCE_DIR}" "${DEST_DIR}" -install_common_skills_from_source "${SOURCE_DIR}" "${DEST_DIR}" -write_stamp "${DEST_DIR}" "${COMMON_SKILLS_REPO_URL}" "${ACTUAL_REF}" +echo "Installing common agent skills from skills-lock.json." +install_from_lock +mkdir -p "$(dirname "${STAMP_FILE}")" +printf "%s +" "${LOCK_HASH}" > "${STAMP_FILE}" diff --git a/script/run b/script/run index 59b578e113..c06a2ffef7 100755 --- a/script/run +++ b/script/run @@ -19,7 +19,8 @@ cd "${REPO_ROOT}" OS_TYPE="$(uname -s)" FEATURES="gui" -INSTALL_COMMON_SKILLS=0 +INSTALL_COMMON_SKILLS=1 +FORCE_COMMON_SKILLS=0 ./script/install_channel_config || echo "Skipping internal channel config installation (no repo access)." @@ -65,7 +66,7 @@ while (( "$#" )); do fi ;; --install-common-skills) - INSTALL_COMMON_SKILLS=1 + FORCE_COMMON_SKILLS=1 shift ;; --release) @@ -93,8 +94,11 @@ while (( "$#" )); do done if [[ "$INSTALL_COMMON_SKILLS" -eq 1 ]]; then - echo "Checking common agent skills version..." - ./script/install_common_skills --if-needed --non-interactive --quiet || echo "Skipping common-skills update." + if [[ "$FORCE_COMMON_SKILLS" -eq 1 ]]; then + ./script/install_common_skills --force --non-interactive || echo "Skipping common-skills update." + else + ./script/install_common_skills --if-needed --non-interactive --quiet || echo "Skipping common-skills update." + fi fi # These cargo features were removed and replaced by environment variables read diff --git a/script/windows/bootstrap.ps1 b/script/windows/bootstrap.ps1 index 0ec2ff5864..53f1d05cd8 100644 --- a/script/windows/bootstrap.ps1 +++ b/script/windows/bootstrap.ps1 @@ -6,12 +6,6 @@ param( $ErrorActionPreference = 'Stop' -if ([string]::IsNullOrWhiteSpace($env:WARP_COMMON_SKILLS_REPO_URL)) { - $commonSkillsRepoUrl = 'https://github.com/warpdotdev/common-skills/' -} else { - $commonSkillsRepoUrl = $env:WARP_COMMON_SKILLS_REPO_URL -} - function Show-Usage { Write-Output 'Usage: .\script\windows\bootstrap.ps1 [-Help] [-InstallCommonSkills]' Write-Output '' @@ -19,17 +13,11 @@ function Show-Usage { Write-Output '' Write-Output 'Options:' Write-Output ' -Help Show this help message.' - Write-Output ' -InstallCommonSkills Install or update common agent skills from warpdotdev/common-skills.' + Write-Output ' -InstallCommonSkills Install or update common agent skills from skills-lock.json.' Write-Output '' Write-Output 'Environment:' Write-Output ' WARP_SKIP_COMMON_SKILLS_INSTALL=1' Write-Output ' Skip installing common agent skills.' - Write-Output ' WARP_COMMON_SKILLS_DEST_DIR=C:\path\to\base-dir' - Write-Output ' Install common skills into C:\path\to\base-dir\.agents\skills without prompting.' - Write-Output ' WARP_COMMON_SKILLS_REPO_URL=C:\path\to\common-skills-or-git-url' - Write-Output ' Use a specific common-skills checkout or repository URL.' - Write-Output ' WARP_COMMON_SKILLS_REF=' - Write-Output ' Use a specific common-skills git ref.' } function Show-BootstrapPreview { @@ -45,7 +33,7 @@ function Show-BootstrapPreview { } elseif ($env:WARP_SKIP_COMMON_SKILLS_INSTALL -eq '1') { Write-Output ' - Skip common agent skills because WARP_SKIP_COMMON_SKILLS_INSTALL=1.' } else { - Write-Output " - Install or update common agent skills from $commonSkillsRepoUrl if needed." + Write-Output ' - Install or update common agent skills from skills-lock.json if needed.' } Write-Output 'Run .\script\windows\bootstrap.ps1 -Help to see options and environment overrides.' diff --git a/skills-lock.json b/skills-lock.json new file mode 100644 index 0000000000..70515a6672 --- /dev/null +++ b/skills-lock.json @@ -0,0 +1,65 @@ +{ + "version": 1, + "skills": { + "create-pr": { + "source": "warpdotdev/common-skills", + "sourceType": "github", + "skillPath": ".agents/skills/create-pr/SKILL.md", + "computedHash": "d9f06f0219b3d402cf1ff3b0ee3a4d6d38f259a0dcf6103a99b1815c2b81d95b" + }, + "diagnose-ci-failures": { + "source": "warpdotdev/common-skills", + "sourceType": "github", + "skillPath": ".agents/skills/diagnose-ci-failures/SKILL.md", + "computedHash": "7a7bbe627bbf747c05e37f9a815ddaedea30a588c452e9279b1305ec172d1006" + }, + "fix-errors": { + "source": "warpdotdev/common-skills", + "sourceType": "github", + "skillPath": ".agents/skills/fix-errors/SKILL.md", + "computedHash": "f5099304ec8e6bc8be578ebc973de31e46ff1e8f0fe671d1641a395a9470ff7a" + }, + "implement-specs": { + "source": "warpdotdev/common-skills", + "sourceType": "github", + "skillPath": ".agents/skills/implement-specs/SKILL.md", + "computedHash": "bd2787a63cfdc917275769ef2d9c7adc701cfaf1a74344b3a6248d4116a8923e" + }, + "resolve-merge-conflicts": { + "source": "warpdotdev/common-skills", + "sourceType": "github", + "skillPath": ".agents/skills/resolve-merge-conflicts/SKILL.md", + "computedHash": "5376b5692901c624e8f20a5a04aeea5f5a94f5168d29852a8a639aded6408f2e" + }, + "review-pr": { + "source": "warpdotdev/common-skills", + "sourceType": "github", + "skillPath": ".agents/skills/review-pr/SKILL.md", + "computedHash": "5bb3ee6ea66cd018fe6bc08d003493fc2abce29441af73e86fd35a590312eaff" + }, + "spec-driven-implementation": { + "source": "warpdotdev/common-skills", + "sourceType": "github", + "skillPath": ".agents/skills/spec-driven-implementation/SKILL.md", + "computedHash": "e334d0f6f0e8fc39055314acad911f36d92d1919372b5e2973cc99d7f8c901b4" + }, + "update-skill": { + "source": "warpdotdev/common-skills", + "sourceType": "github", + "skillPath": ".agents/skills/update-skill/SKILL.md", + "computedHash": "1e23c5a5c37ed084eced7fa507031e3cdb8e23f09cd5d004e00efd6f66bf200f" + }, + "write-product-spec": { + "source": "warpdotdev/common-skills", + "sourceType": "github", + "skillPath": ".agents/skills/write-product-spec/SKILL.md", + "computedHash": "f20d141e67057570b1fe7c902d5e563415c5ae4a72027d069550ff5b4c5917f2" + }, + "write-tech-spec": { + "source": "warpdotdev/common-skills", + "sourceType": "github", + "skillPath": ".agents/skills/write-tech-spec/SKILL.md", + "computedHash": "702924ae98de5466f452eba2effbd004de5edd91617097372c4725a5b5035919" + } + } +} diff --git a/specs/common-skills-installation/TECH.md b/specs/common-skills-installation/TECH.md new file mode 100644 index 0000000000..a804938f2d --- /dev/null +++ b/specs/common-skills-installation/TECH.md @@ -0,0 +1,87 @@ +# Common Skills Installation — Tech Spec + +## Context +This PR replaces the custom `.agents/common-skills.lock` flow with the standard project lock managed by `npx skills`. The checked-in `skills-lock.json` records each common skill from `warpdotdev/common-skills`, including its source, skill path, and content hash (`skills-lock.json:1`). The repository also checks in the restored `.agents/skills/*` copies so local and cloud agents can discover skills directly from the checkout. + +The main install entrypoint is `script/install_common_skills`. It points at `skills-lock.json` (`script/install_common_skills:6`) and stores a local, untracked stamp under `.git/warp/common-skills-lock.hash` (`script/install_common_skills:7`). The script hashes the lock (`script/install_common_skills:38`) and skips work when that hash matches the stamp (`script/install_common_skills:118`). When the stamp is missing or stale, it restores from the lock by running `npx --yes skills@latest experimental_install` (`script/install_common_skills:71`) and writes the new stamp (`script/install_common_skills:126`). + +`script/run` now checks common skills before launching a local build. It enables the check by default (`script/run:22`) and calls `script/install_common_skills --if-needed --non-interactive --quiet` unless the user explicitly passes `--install-common-skills`, which forces a restore (`script/run:68`, `script/run:96`). Bootstrap remains opt-in through `./script/bootstrap --install-common-skills` and delegates to the same installer (`script/bootstrap:21`, `script/bootstrap:77`). `WARP.md` documents the standard update command and the files reviewers should expect to change (`WARP.md:41`). + +## Diagrams +### Local agent installation and update flow +```mermaid +flowchart TD + A["warpdotdev/warp checkout"] --> B["skills-lock.json"] + A --> C[".agents/skills/*"] + + B --> D["script/run"] + D --> E["script/install_common_skills --if-needed --quiet"] + E --> F["Hash skills-lock.json"] + F --> G{"Does .git/warp/common-skills-lock.hash match?"} + + G -->|Yes| H["Skip restore"] + H --> I["Continue local build/run"] + + G -->|No| J["npx --yes skills@latest experimental_install"] + J --> K["Read skills-lock.json"] + K --> L["Fetch locked skills from warpdotdev/common-skills"] + L --> M["Restore .agents/skills/*"] + M --> N["Write .git/warp/common-skills-lock.hash"] + N --> I + + O["Developer updates common skills"] --> P["npx --yes skills@latest update -p -y"] + P --> Q["Update skills-lock.json hashes"] + P --> R["Update changed .agents/skills/* files"] + Q --> S["Commit lock + skill changes"] + R --> S + S --> A +``` + +### Oz cloud agent environment setup flow +```mermaid +flowchart TD + A["Oz Claude cloud-agent run requested"] --> B["Oz selects environment"] + B --> C["Environment clones or syncs warpdotdev/warp"] + C --> D["Checkout contains skills-lock.json and .agents/skills/*"] + + D --> E["Environment setup invokes ./script/install_common_skills --if-needed"] + E --> F["Hash skills-lock.json in cloud checkout"] + F --> G{"Does cloud-local stamp match?"} + + G -->|Yes| H["Skip restore"] + G -->|No or first setup| I["npx --yes skills@latest experimental_install"] + I --> J["Read skills-lock.json"] + J --> K["Fetch locked skills from warpdotdev/common-skills"] + K --> L["Restore .agents/skills/*"] + L --> M["Write .git/warp/common-skills-lock.hash"] + + H --> N["Start Claude agent"] + M --> N + N --> O["Repo-local skills are discoverable"] + N --> P["Optional explicit skill spec"] + P --> Q["Example: --skill warpdotdev/warp:create-pr"] +``` + +## Proposed changes +The implementation should keep `skills-lock.json` as the single source of truth for common skills installed from `warpdotdev/common-skills`. The repo should not maintain a second custom lock format or a separate GitHub workflow for scheduled common-skill updates. + +`script/install_common_skills` owns restoration from the lock. It should remain small and deterministic: compute a hash for `skills-lock.json`, compare it with a checkout-local stamp, run `npx --yes skills@latest experimental_install` only when needed, and update the stamp after a successful restore. The stamp belongs under `.git` so running the script does not create or modify tracked files unless the lock itself has been updated intentionally. + +`script/run` should call the installer before building so local developer runs pick up lock changes automatically. This makes `script/run` the dependency-update check point requested during review: when a branch changes `skills-lock.json`, the next run restores the matching skill contents without requiring a separate workflow. `--install-common-skills` is retained as a force-install escape hatch. + +`script/bootstrap --install-common-skills` should continue to be an opt-in bootstrap path and delegate to the same installer. This keeps platform setup and normal run setup consistent. + +For Oz cloud runs, this PR provides the repository-side installer that environment setup should call after cloning or syncing the repository and before starting the Claude agent. A fresh environment will have no `.git/warp/common-skills-lock.hash`, so `./script/install_common_skills --if-needed` restores from `skills-lock.json` once. A reused environment skips the restore when the stamp matches the checked-out lock. After this step, the Claude agent can discover repo-local checked-in skills, and Oz can still pass an explicit skill spec such as `warpdotdev/warp:create-pr` when the run should start from a specific skill. The Oz environment hook itself lives outside this repo; the implementation boundary here is making the repo checkout self-sufficient and idempotent when that hook invokes the script. + +Updates to common skills should be explicit developer actions: run `npx --yes skills@latest update -p -y`, review the generated `skills-lock.json` and `.agents/skills/*` changes, and commit them together. This preserves dependency-review semantics without adding repository-specific scheduled automation. + +## Testing and validation +Validate the shell changes with `bash -n script/install_common_skills script/run script/bootstrap`. + +Validate the Windows bootstrap script parses with PowerShell: `pwsh -NoProfile -Command '$null = [scriptblock]::Create((Get-Content -Raw "script/windows/bootstrap.ps1"))'`. + +Validate the restore path by running `./script/install_common_skills --if-needed --quiet` from a checkout without a matching local stamp. It should run `npx skills experimental_install`, restore the locked `.agents/skills/*` contents, and write `.git/warp/common-skills-lock.hash`. + +Validate the skip path by running `./script/install_common_skills --if-needed --quiet` again. It should exit successfully without output and without changing the worktree. + +Validate update behavior by running `npx --yes skills@latest update -p -y` in a test checkout or intentional update branch. If upstream common skills changed, the diff should be limited to `skills-lock.json` and the affected `.agents/skills/*` files. From e2abcf717c06d98572777e3420a4e0e34260d79b Mon Sep 17 00:00:00 2001 From: Zachary Lloyd Date: Sat, 9 May 2026 13:03:15 -0600 Subject: [PATCH 6/6] Address common skills installer review feedback Avoid forwarding -y/--yes to the Windows bootstrap wrapper, and pin the npx skills CLI used by automatic common-skills restores. Update the tech spec and WARP.md to document the pinned installer/update flow. Co-Authored-By: Oz --- WARP.md | 2 +- script/bootstrap | 6 ++++-- script/install_common_skills | 6 +++--- specs/common-skills-installation/TECH.md | 16 ++++++++-------- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/WARP.md b/WARP.md index 6a9f5de0b7..835a031eb3 100644 --- a/WARP.md +++ b/WARP.md @@ -43,7 +43,7 @@ Environment variables: - `./script/install_cargo_build_deps` - Install Cargo build dependencies - `./script/install_cargo_test_deps` - Install Cargo test dependencies -`skills-lock.json` is the standard project lock file managed by `npx skills`. `script/run` checks this lock before building and restores the checked-in project skills with `npx skills experimental_install` when the local install stamp is stale. To update the locked common skills, run `npx --yes skills@latest update -p -y` and commit the resulting `skills-lock.json` and `.agents/skills` changes. +`skills-lock.json` is the standard project lock file managed by `npx skills`. `script/run` checks this lock before building and restores the checked-in project skills with the pinned `skills@1.5.6` CLI when the local install stamp is stale. To update the locked common skills, run `npx --yes skills@1.5.6 update -p -y` and commit the resulting `skills-lock.json` and `.agents/skills` changes. ## Architecture Overview diff --git a/script/bootstrap b/script/bootstrap index 8ef43bd941..cea3f72aa3 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -61,7 +61,9 @@ for arg in "$@"; do ;; -y|--yes) export WARP_SKIP_SUDO_PROMPT=1 - PLATFORM_ARGS+=("${arg}") + if [[ ! "$OS_TYPE" =~ ^(MINGW64_NT|MSYS_NT) ]]; then + PLATFORM_ARGS+=("${arg}") + fi ;; --install-common-skills) INSTALL_COMMON_SKILLS=1 @@ -86,7 +88,7 @@ elif [[ "$OS_TYPE" = "Linux" ]]; then print_bootstrap_preview "Linux" ./script/linux/bootstrap "${PLATFORM_ARGS[@]}" maybe_install_common_skills -elif [[ "$OS_TYPE" =~ ^[MINGW64_NT|MSYS_NT] ]]; then +elif [[ "$OS_TYPE" =~ ^(MINGW64_NT|MSYS_NT) ]]; then if [[ "${INSTALL_COMMON_SKILLS}" -eq 1 ]]; then ./script/windows/bootstrap.ps1 "${PLATFORM_ARGS[@]}" -InstallCommonSkills else diff --git a/script/install_common_skills b/script/install_common_skills index 0c690ac4df..43ca57141c 100755 --- a/script/install_common_skills +++ b/script/install_common_skills @@ -5,6 +5,7 @@ set -eo pipefail REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd)" LOCK_FILE="${REPO_ROOT}/skills-lock.json" STAMP_RELATIVE_PATH="warp/common-skills-lock.hash" +SKILLS_CLI_VERSION="1.5.6" IF_NEEDED=0 FORCE=0 @@ -68,7 +69,7 @@ stamp_hash() { install_from_lock() { ( cd "${REPO_ROOT}" - npx --yes skills@latest experimental_install + npx --yes "skills@${SKILLS_CLI_VERSION}" experimental_install ) } @@ -123,5 +124,4 @@ fi echo "Installing common agent skills from skills-lock.json." install_from_lock mkdir -p "$(dirname "${STAMP_FILE}")" -printf "%s -" "${LOCK_HASH}" > "${STAMP_FILE}" +printf "%s\n" "${LOCK_HASH}" > "${STAMP_FILE}" diff --git a/specs/common-skills-installation/TECH.md b/specs/common-skills-installation/TECH.md index a804938f2d..950c4a647f 100644 --- a/specs/common-skills-installation/TECH.md +++ b/specs/common-skills-installation/TECH.md @@ -3,7 +3,7 @@ ## Context This PR replaces the custom `.agents/common-skills.lock` flow with the standard project lock managed by `npx skills`. The checked-in `skills-lock.json` records each common skill from `warpdotdev/common-skills`, including its source, skill path, and content hash (`skills-lock.json:1`). The repository also checks in the restored `.agents/skills/*` copies so local and cloud agents can discover skills directly from the checkout. -The main install entrypoint is `script/install_common_skills`. It points at `skills-lock.json` (`script/install_common_skills:6`) and stores a local, untracked stamp under `.git/warp/common-skills-lock.hash` (`script/install_common_skills:7`). The script hashes the lock (`script/install_common_skills:38`) and skips work when that hash matches the stamp (`script/install_common_skills:118`). When the stamp is missing or stale, it restores from the lock by running `npx --yes skills@latest experimental_install` (`script/install_common_skills:71`) and writes the new stamp (`script/install_common_skills:126`). +The main install entrypoint is `script/install_common_skills`. It points at `skills-lock.json` (`script/install_common_skills:6`) and stores a local, untracked stamp under `.git/warp/common-skills-lock.hash` (`script/install_common_skills:7`). The script hashes the lock (`script/install_common_skills:39`) and skips work when that hash matches the stamp (`script/install_common_skills:119`). When the stamp is missing or stale, it restores from the lock by running `npx --yes "skills@${SKILLS_CLI_VERSION}" experimental_install` (`script/install_common_skills:72`) and writes the new stamp (`script/install_common_skills:127`). `script/run` now checks common skills before launching a local build. It enables the check by default (`script/run:22`) and calls `script/install_common_skills --if-needed --non-interactive --quiet` unless the user explicitly passes `--install-common-skills`, which forces a restore (`script/run:68`, `script/run:96`). Bootstrap remains opt-in through `./script/bootstrap --install-common-skills` and delegates to the same installer (`script/bootstrap:21`, `script/bootstrap:77`). `WARP.md` documents the standard update command and the files reviewers should expect to change (`WARP.md:41`). @@ -22,14 +22,14 @@ flowchart TD G -->|Yes| H["Skip restore"] H --> I["Continue local build/run"] - G -->|No| J["npx --yes skills@latest experimental_install"] + G -->|No| J["npx --yes skills@1.5.6 experimental_install"] J --> K["Read skills-lock.json"] K --> L["Fetch locked skills from warpdotdev/common-skills"] L --> M["Restore .agents/skills/*"] M --> N["Write .git/warp/common-skills-lock.hash"] N --> I - O["Developer updates common skills"] --> P["npx --yes skills@latest update -p -y"] + O["Developer updates common skills"] --> P["npx --yes skills@1.5.6 update -p -y"] P --> Q["Update skills-lock.json hashes"] P --> R["Update changed .agents/skills/* files"] Q --> S["Commit lock + skill changes"] @@ -49,7 +49,7 @@ flowchart TD F --> G{"Does cloud-local stamp match?"} G -->|Yes| H["Skip restore"] - G -->|No or first setup| I["npx --yes skills@latest experimental_install"] + G -->|No or first setup| I["npx --yes skills@1.5.6 experimental_install"] I --> J["Read skills-lock.json"] J --> K["Fetch locked skills from warpdotdev/common-skills"] K --> L["Restore .agents/skills/*"] @@ -65,7 +65,7 @@ flowchart TD ## Proposed changes The implementation should keep `skills-lock.json` as the single source of truth for common skills installed from `warpdotdev/common-skills`. The repo should not maintain a second custom lock format or a separate GitHub workflow for scheduled common-skill updates. -`script/install_common_skills` owns restoration from the lock. It should remain small and deterministic: compute a hash for `skills-lock.json`, compare it with a checkout-local stamp, run `npx --yes skills@latest experimental_install` only when needed, and update the stamp after a successful restore. The stamp belongs under `.git` so running the script does not create or modify tracked files unless the lock itself has been updated intentionally. +`script/install_common_skills` owns restoration from the lock. It should remain small and deterministic: compute a hash for `skills-lock.json`, compare it with a checkout-local stamp, run `npx --yes skills@1.5.6 experimental_install` only when needed, and update the stamp after a successful restore. The stamp belongs under `.git` so running the script does not create or modify tracked files unless the lock itself has been updated intentionally. `script/run` should call the installer before building so local developer runs pick up lock changes automatically. This makes `script/run` the dependency-update check point requested during review: when a branch changes `skills-lock.json`, the next run restores the matching skill contents without requiring a separate workflow. `--install-common-skills` is retained as a force-install escape hatch. @@ -73,15 +73,15 @@ The implementation should keep `skills-lock.json` as the single source of truth For Oz cloud runs, this PR provides the repository-side installer that environment setup should call after cloning or syncing the repository and before starting the Claude agent. A fresh environment will have no `.git/warp/common-skills-lock.hash`, so `./script/install_common_skills --if-needed` restores from `skills-lock.json` once. A reused environment skips the restore when the stamp matches the checked-out lock. After this step, the Claude agent can discover repo-local checked-in skills, and Oz can still pass an explicit skill spec such as `warpdotdev/warp:create-pr` when the run should start from a specific skill. The Oz environment hook itself lives outside this repo; the implementation boundary here is making the repo checkout self-sufficient and idempotent when that hook invokes the script. -Updates to common skills should be explicit developer actions: run `npx --yes skills@latest update -p -y`, review the generated `skills-lock.json` and `.agents/skills/*` changes, and commit them together. This preserves dependency-review semantics without adding repository-specific scheduled automation. +Updates to common skills should be explicit developer actions: run `npx --yes skills@1.5.6 update -p -y`, review the generated `skills-lock.json` and `.agents/skills/*` changes, and commit them together. This preserves dependency-review semantics without adding repository-specific scheduled automation. ## Testing and validation Validate the shell changes with `bash -n script/install_common_skills script/run script/bootstrap`. Validate the Windows bootstrap script parses with PowerShell: `pwsh -NoProfile -Command '$null = [scriptblock]::Create((Get-Content -Raw "script/windows/bootstrap.ps1"))'`. -Validate the restore path by running `./script/install_common_skills --if-needed --quiet` from a checkout without a matching local stamp. It should run `npx skills experimental_install`, restore the locked `.agents/skills/*` contents, and write `.git/warp/common-skills-lock.hash`. +Validate the restore path by running `./script/install_common_skills --if-needed --quiet` from a checkout without a matching local stamp. It should run the pinned `skills@1.5.6` restore command, restore the locked `.agents/skills/*` contents, and write `.git/warp/common-skills-lock.hash`. Validate the skip path by running `./script/install_common_skills --if-needed --quiet` again. It should exit successfully without output and without changing the worktree. -Validate update behavior by running `npx --yes skills@latest update -p -y` in a test checkout or intentional update branch. If upstream common skills changed, the diff should be limited to `skills-lock.json` and the affected `.agents/skills/*` files. +Validate update behavior by running `npx --yes skills@1.5.6 update -p -y` in a test checkout or intentional update branch. If upstream common skills changed, the diff should be limited to `skills-lock.json` and the affected `.agents/skills/*` files.