
Pick Copilot Tag
- 2 installs
- 4.2k repo stars
- Updated August 5, 2026
- posit-dev/positron
pick-copilot-tag is a Claude Code skill for ai & agent building.
About
Runs a script that reads the Code OSS version, extracts API proposals, and checks copilot-chat release tags for compatibility. A Positron maintainer uses it when deciding which copilot-chat tag to merge after an upstream update or when a build rejects it as incompatible.
- Auto-discovers compatible tag series from package.json and the source tree
- Reports the latest OK tag plus which proposals break in newer tags
Pick Copilot Tag by the numbers
- 2 all-time installs (skills.sh)
- +1 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #1,138 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/posit-dev/positron --skill pick-copilot-tagAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2 |
|---|---|
| repo stars | ★ 4.2k |
| Last updated | August 5, 2026 |
| Repository | posit-dev/positron ↗ |
How do I helps with ai & agent building tasks during AI-assisted development.?
Finds which microsoft/vscode-copilot-chat release tag is API-proposal compatible with a given Positron build by running a proposal-check script.
Who is it for?
A solo builder working on ai & agent building tasks who needs structured help with pick copilot tag.
Skip if: Teams with no ai & agent building needs, or anyone wanting a generic chat assistant without this specific workflow.
When should I use this skill?
When you need to helps with ai & agent building tasks during AI-assisted development., or when pick-copilot-tag is a claude code skill for ai & agent building.
What you get
Structured output aligned to pick-copilot-tag: pick-copilot-tag, AI & Agent Building.
Files
Pick Copilot Tag
Determine which microsoft/vscode-copilot-chat release tag is compatible with a given Positron build by checking API proposal version compatibility.
When to Use
Use this skill when:
- Deciding which copilot-chat tag to merge after an upstream Code OSS update
- A release build rejects copilot-chat with "API proposals not compatible"
- Upgrading copilot-chat and need to find the latest compatible tag
Prerequisites
- GitHub CLI (
gh) installed and authenticated jqandpython3available
Workflow
Step 1: Run the Check
From the Positron repo root, run the script with no arguments. It will automatically read package.json for the Code OSS version, extract proposals from the source tree, discover compatible tag series, and check them all:
.claude/skills/pick-copilot-tag/scripts/check-proposals.shFor checking against a built Positron app instead of the source tree:
.claude/skills/pick-copilot-tag/scripts/check-proposals.sh --app /Applications/Positron.appTo check against a specific Positron release (fetches both proposals and the Code OSS version from the release tag on GitHub):
.claude/skills/pick-copilot-tag/scripts/check-proposals.sh --positron-version 2026.03.0To check a specific tag series (skips auto-discovery):
.claude/skills/pick-copilot-tag/scripts/check-proposals.sh --tag-series v0.37Flags can be combined, e.g. --positron-version 2026.03.0 --tag-series v0.37.
Step 2: Report Results
The script outputs each tag as OK or BAD with specific mismatches. Report:
- The latest compatible tag (first OK in descending version order)
- What breaks in newer tags (which proposals changed)
- A recommendation
Use -v / --verbose to show the full proposals list instead of just the count. Use --pre-releases to also check date-based pre-release tags (skipped by default).
Example Output
Positron proposals: 9 versioned (from src/vs/.../extensionsApiProposals.ts)
Code OSS version: 1.109.0
Checking recent tag series for engine compatibility:
v0.36 -> ^1.108.0 (compatible)
v0.37 -> ^1.109.0 (compatible)
v0.38 -> ^1.110.0 (needs Code OSS >= 1.110.0)
--- v0.37 ---
Releases (10 tags):
BAD v0.37.9
chatHooks@6 (not in Positron)
chatParticipantPrivate@13 (Positron has chatParticipantPrivate@12)
BAD v0.37.6
chatHooks@6 (not in Positron)
OK v0.37.5
Pre-releases (41 tags, skipped -- use --pre-releases to check)
Latest compatible release: v0.37.5API Proposal Version Compatibility
How the check works
VS Code extensions can use "proposed APIs" -- unstable APIs not yet finalized. Each proposal can optionally carry a version number (e.g., chatProvider@4).
Positron's product.json contains an extensionsEnabledWithApiProposalVersion list. Extensions on this list get strict version enforcement: every versioned proposal in the extension's package.json must exactly match the version compiled into the Positron build.
- Dev builds (
quality: null) skip this check entirely - Release builds enforce it -- mismatches block extension activation
What causes failures
1. New proposal added upstream -- e.g., chatHooks@6 added in v0.37.6, but Positron doesn't have chatHooks at all 2. Version bumped upstream -- e.g., chatParticipantPrivate@12 -> @13, but Positron still has @12
Both produce the same error:
ERR: This extension is using the API proposals 'X' and 'Y'
that are not compatible with the current version of VS Code.Where proposals live
- In the extension:
package.json->enabledApiProposalsarray - In Positron: compiled into
sharedProcessMain.js(extracted at build time
from src/vs/platform/extensions/common/extensionsApiProposals.ts)
- In product.json:
extensionsEnabledWithApiProposalVersioncontrols which
extensions get the strict check
Why engine version isn't enough
Engine version match is necessary but not sufficient. There are two ways it can mislead:
1. Within a series: All tags in a minor series (e.g., v0.37.0 through v0.37.9) target the same engines.vscode range (e.g., ^1.109.0). But Microsoft cherry-picks features into release branches between patches, and those features can introduce new proposals or bump existing ones.
2. Across series: Multiple minor series can target the same engine range. For example, both v0.37.x and v0.38.x targeted ^1.109.0, but v0.38 used proposals (chatHooks, bumped chatParticipantPrivate) from a pre-release VS Code that didn't exist in the stable 1.109 base. See posit-dev/positron-copilot-chat#15 for the full story.
The only reliable check is comparing the enabledApiProposals arrays.
#!/usr/bin/env bash
# Check upstream release tags for API proposal compatibility with a Positron build.
#
# Usage:
# ./check-proposals.sh # auto-detect from repo
# ./check-proposals.sh --app /Applications/Positron.app # check a built app
# ./check-proposals.sh --positron-version 2026.03.0 # check a release
# ./check-proposals.sh --tag-series v0.37 # check one tag series
#
# With no arguments, reads package.json for the Code OSS version, extracts
# proposals from the source tree, and discovers compatible tag series
# automatically.
#
# Options:
# --app <path> Check against a built Positron app bundle
# --tag-series <prefix> Check only this tag series (e.g. v0.37)
# --positron-version <version> Check against a Positron release (e.g. 2026.03.0)
# Looks up the release tag on GitHub, retrieves the
# Code OSS version and proposals from that build.
# --pre-releases Also check date-based pre-release tags (default: releases only)
# -v, --verbose Show full list of Positron proposals (default: count only)
#
# Requires: gh, jq, python3
set -euo pipefail
REPO="microsoft/vscode-copilot-chat"
PROPOSALS_TS="src/vs/platform/extensions/common/extensionsApiProposals.ts"
POSITRON_REPO="posit-dev/positron"
VERBOSE=false
PRE_RELEASES=false
POSITRON_VERSION=""
APP_PATH=""
TAG_PREFIX=""
die() { echo "error: $*" >&2; exit 1; }
# --- Parse flags ---------------------------------------------------------------
while [[ $# -gt 0 ]]; do
case "$1" in
-v|--verbose) VERBOSE=true; shift ;;
--pre-releases) PRE_RELEASES=true; shift ;;
--positron-version)
[[ -n "${2:-}" ]] || die "--positron-version requires a version (e.g. 2026.03.0)"
POSITRON_VERSION="$2"; shift 2 ;;
--app)
[[ -n "${2:-}" ]] || die "--app requires a path to a Positron app bundle"
APP_PATH="$2"; shift 2 ;;
--tag-series)
[[ -n "${2:-}" ]] || die "--tag-series requires a prefix (e.g. v0.37)"
TAG_PREFIX="$2"; shift 2 ;;
-*) die "Unknown option: $1" ;;
*) die "Unexpected argument: $1. Use --app, --tag-series, or --positron-version." ;;
esac
done
# --- Resolve Positron release tag ---------------------------------------------
# Given a Positron version (e.g. 2026.03.0 or 2026.03.0-212), find the
# published release tag on GitHub and extract its Code OSS version.
# Sets: _POSITRON_TAG, _POSITRON_CODE_VERSION
resolve_positron_version() {
local version="$1"
# If the version already includes a build number, use it directly.
# Otherwise, find the latest published release matching the prefix.
local tag
if [[ "$version" =~ ^[0-9]{4}\.[0-9]{2}\.[0-9]+-[0-9]+$ ]]; then
tag="$version"
elif [[ "$version" =~ ^[0-9]{4}\.[0-9]{2}\.[0-9]+$ ]]; then
tag=$(gh api "repos/$POSITRON_REPO/releases" --paginate \
--jq ".[].tag_name | select(startswith(\"$version-\"))" \
| sort -t- -k2 -rn | head -1)
[[ -n "$tag" ]] || die "No published release found for Positron $version"
else
die "--positron-version must be YYYY.MM.PATCH or YYYY.MM.PATCH-BUILD (e.g. 2026.03.0), got: $version"
fi
echo "Positron release: $tag"
# Fetch Code OSS version from that tag's package.json
local pkg_content
pkg_content=$(gh api "repos/$POSITRON_REPO/contents/package.json?ref=$tag" \
--jq '.content' 2>/dev/null) || die "Could not fetch package.json from $POSITRON_REPO at tag $tag"
[[ -n "$pkg_content" ]] || die "Empty package.json content from $POSITRON_REPO at tag $tag"
_POSITRON_TAG="$tag"
_POSITRON_CODE_VERSION=$(echo "$pkg_content" | base64 -d | jq -r '.version')
echo "Code OSS version: $_POSITRON_CODE_VERSION"
}
# --- Resolve Positron proposals ------------------------------------------------
# Fetch proposals from a remote Positron tag on GitHub.
resolve_proposals_from_tag() {
local tag="$1"
local content
content=$(gh api "repos/$POSITRON_REPO/contents/$PROPOSALS_TS?ref=$tag" \
--jq '.content' 2>/dev/null) || die "Could not fetch $PROPOSALS_TS from $POSITRON_REPO at tag $tag"
[[ -n "$content" ]] || die "Empty proposals file from $POSITRON_REPO at tag $tag"
echo "$content" | base64 -d | python3 -c "
import re, sys
content = sys.stdin.read()
for m in re.finditer(r'(\w+)\s*:\s*\{[^}]*version\s*:\s*(\d+)', content):
print(f'{m.group(1)}@{m.group(2)}')
" | sort -u
}
resolve_proposals_from_app() {
local app_path="$1"
[[ -d "$app_path" || "$app_path" == *.app ]] || die "Not an app bundle or directory: $app_path"
local js
js=$(find "$app_path" -name 'sharedProcessMain.js' -print -quit 2>/dev/null)
[[ -n "$js" ]] || die "Could not find sharedProcessMain.js inside $app_path"
# Extract name@version from the proposals map structure. The JS may
# be minified (name:{proposal:"...",version:N}) or pretty-printed
# with newlines and indentation, so allow optional whitespace.
python3 -c "
import re, sys
content = open(sys.argv[1]).read()
for m in re.finditer(r'(\w+):\s*\{\s*proposal:\s*\"[^\"]+\"\s*,\s*version:\s*(\d+)\s*\}', content):
print(f'{m.group(1)}@{m.group(2)}')
" "$js" | sort -u
}
resolve_proposals_from_source() {
local ts_file="$1"
[[ -f "$ts_file" ]] || die "Proposals file not found: $ts_file"
python3 -c "
import re, sys
content = open(sys.argv[1]).read()
for m in re.finditer(r'(\w+)\s*:\s*\{[^}]*version\s*:\s*(\d+)', content):
print(f'{m.group(1)}@{m.group(2)}')
" "$ts_file" | sort -u
}
# --- Discover compatible tag series from Code OSS version ---------------------
discover_tag_series() {
local code_oss_version="$1"
local code_oss_minor
code_oss_minor=$(echo "$code_oss_version" | cut -d. -f2)
# List all unique tag series (check last 5 minor versions)
local all_series
all_series=$(gh api "repos/$REPO/git/matching-refs/tags/v" --paginate \
--jq '.[].ref | ltrimstr("refs/tags/")' \
| grep -oE '^v[0-9]+\.[0-9]+' | sort -uV | tail -5)
[[ -n "$all_series" ]] || die "Could not list tag series from $REPO"
echo "Checking recent tag series for engine compatibility:"
local candidates=""
for series in $all_series; do
local content
content=$(gh api "repos/$REPO/contents/package.json?ref=${series}.0" \
--jq '.content' 2>/dev/null) || continue
[[ -n "$content" ]] || continue
local engine
engine=$(echo "$content" | base64 -d 2>/dev/null \
| jq -r '.engines.vscode // "unknown"' 2>/dev/null) || continue
# Parse engine minor version from e.g. ^1.109.0
local engine_minor
engine_minor=$(echo "$engine" | grep -oE '[0-9]+\.[0-9]+' | head -1 | cut -d. -f2)
[[ -n "$engine_minor" ]] || continue
if [[ "$engine_minor" -le "$code_oss_minor" ]]; then
echo " $series -> $engine (compatible)"
candidates+="$series"$'\n'
elif [[ "$engine_minor" -le "$((code_oss_minor + 1))" ]]; then
# The .0 release needs a newer engine, but date-based pre-releases
# in this series may target an older engine (they predate .0).
echo " $series -> $engine (pre-releases may be compatible)"
candidates+="$series"$'\n'
else
local min_version
min_version=$(echo "$engine" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
echo " $series -> $engine (needs Code OSS >= ${min_version:-$engine})"
fi
done
# Return candidates newest-first so we check the highest series first.
_CANDIDATES=$(echo "$candidates" | grep -v '^$' | sort -rV || true)
}
# --- Check a list of tags ----------------------------------------------------
# Sets _FOUND_OK to the first (newest) compatible tag, or "" if none found.
check_tag_list() {
local tags="$1"
local positron_proposals="$2"
_FOUND_OK=""
local total checked=0
total=$(echo "$tags" | wc -l | tr -d ' ')
# Progress indicator (only when stderr is a terminal).
local show_progress=false
[[ -t 2 ]] && show_progress=true
_progress() {
if [[ "$show_progress" == true ]]; then
printf '\r\033[K checking %d/%d: %s ...' "$@" >&2
fi
}
_clear_progress() {
if [[ "$show_progress" == true ]]; then
printf '\r\033[K' >&2
fi
}
# Track consecutive skips to print a summary instead of one line per tag.
local skip_count=0 skip_first="" skip_last="" skip_reason=""
_flush_skips() {
if [[ "$skip_count" -eq 0 ]]; then return; fi
_clear_progress
if [[ "$skip_count" -eq 1 ]]; then
echo "SKIP $skip_first ($skip_reason)"
else
echo "SKIP $skip_first .. $skip_last ($skip_count tags, $skip_reason)"
fi
skip_count=0 skip_first="" skip_last="" skip_reason=""
}
for tag in $tags; do
checked=$((checked + 1))
_progress "$checked" "$total" "$tag"
local content
content=$(gh api "repos/$REPO/contents/package.json?ref=$tag" \
--jq '.content' 2>/dev/null) || continue
[[ -n "$content" ]] || continue
# Parse engine and proposals in one shot
local parsed
parsed=$(echo "$content" | base64 -d 2>/dev/null | jq -r '
(.engines.vscode // "") as $engine |
($engine | capture("(?<maj>[0-9]+)\\.(?<min>[0-9]+)") // null) as $m |
(if $m then $m.min else "" end),
$engine,
([(.enabledApiProposals // [])[] | select(contains("@"))] | sort | .[])
' 2>/dev/null) || continue
local tag_engine_minor tag_engine ext_proposals
tag_engine_minor=$(echo "$parsed" | sed -n '1p')
tag_engine=$(echo "$parsed" | sed -n '2p')
ext_proposals=$(echo "$parsed" | tail -n +3)
# Check per-tag engine compatibility
if [[ -n "$_CODE_OSS_MINOR" && -n "$tag_engine_minor" \
&& "$tag_engine_minor" -gt "$_CODE_OSS_MINOR" ]]; then
local min_v
min_v=$(echo "$tag_engine" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
skip_count=$((skip_count + 1))
[[ -z "$skip_first" ]] && skip_first="$tag"
skip_last="$tag"
skip_reason="needs Code OSS >= ${min_v:-$tag_engine}"
continue
fi
# Flush any accumulated skips before printing a non-skip result
_flush_skips
_clear_progress
local issues=""
while IFS= read -r prop; do
[[ -z "$prop" ]] && continue
if ! echo "$positron_proposals" | grep -qxF "$prop"; then
local name="${prop%%@*}"
local match
match=$(echo "$positron_proposals" | grep -E "^${name}@" || true)
if [[ -n "$match" ]]; then
issues+=" $prop (Positron has $match)"$'\n'
else
issues+=" $prop (not in Positron)"$'\n'
fi
fi
done <<< "$ext_proposals"
if [[ -z "$issues" ]]; then
echo "OK $tag"
_FOUND_OK="$tag"
_clear_progress
return
else
echo "BAD $tag"
printf '%s' "$issues"
fi
done
_flush_skips
_clear_progress
}
# --- Check a single tag series ------------------------------------------------
check_series() {
local tag_prefix="$1"
local positron_proposals="$2"
echo ""
echo "--- $tag_prefix ---"
local all_tags
all_tags=$(gh api "repos/$REPO/git/matching-refs/tags/$tag_prefix." --paginate \
--jq '.[].ref | ltrimstr("refs/tags/")' \
| grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \
| sort -rV)
[[ -n "$all_tags" ]] || { echo "No tags found matching $tag_prefix.*"; return; }
# Separate semver releases (1-3 digit patch) from date-based pre-releases (4+ digits)
local release_tags prerelease_tags
release_tags=$(echo "$all_tags" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]{1,3}$' || true)
prerelease_tags=$(echo "$all_tags" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]{4,}$' || true)
if [[ -n "$release_tags" ]]; then
local count
count=$(echo "$release_tags" | wc -l | tr -d ' ')
echo "Releases ($count tags):"
check_tag_list "$release_tags" "$positron_proposals"
if [[ -n "$_FOUND_OK" && -z "$_LATEST_OK" ]]; then
_LATEST_OK="$_FOUND_OK"
fi
fi
if [[ -n "$prerelease_tags" && "$PRE_RELEASES" == true ]]; then
local count
count=$(echo "$prerelease_tags" | wc -l | tr -d ' ')
echo "Pre-releases ($count tags):"
check_tag_list "$prerelease_tags" "$positron_proposals"
if [[ -n "$_FOUND_OK" && -z "$_LATEST_PRERELEASE" ]]; then
_LATEST_PRERELEASE="$_FOUND_OK"
fi
elif [[ -n "$prerelease_tags" ]]; then
local count
count=$(echo "$prerelease_tags" | wc -l | tr -d ' ')
echo "Pre-releases ($count tags, skipped -- use --pre-releases to check)"
fi
}
# --- Main ---------------------------------------------------------------------
# Globals set by functions:
# _CANDIDATES - newline-separated tag series (set by discover_tag_series)
# _CODE_OSS_MINOR - Code OSS minor version for per-tag engine checks
# _LATEST_OK - highest compatible release tag (set by check_series)
# _LATEST_PRERELEASE - highest compatible pre-release tag (set by check_series)
_CODE_OSS_MINOR=""
_LATEST_OK=""
_LATEST_PRERELEASE=""
# Validate flag combinations
if [[ -n "$POSITRON_VERSION" && -n "$APP_PATH" ]]; then
die "Use --positron-version to check a remote release, or --app to check a local build, but not both"
fi
# Resolve proposals from the chosen source
if [[ -n "$POSITRON_VERSION" ]]; then
resolve_positron_version "$POSITRON_VERSION"
code_oss_version="$_POSITRON_CODE_VERSION"
_CODE_OSS_MINOR=$(echo "$code_oss_version" | cut -d. -f2)
positron_proposals=$(resolve_proposals_from_tag "$_POSITRON_TAG")
proposals_label="$POSITRON_REPO@$_POSITRON_TAG"
elif [[ -n "$APP_PATH" ]]; then
positron_proposals=$(resolve_proposals_from_app "$APP_PATH")
proposals_label="$APP_PATH"
else
[[ -f "$PROPOSALS_TS" ]] || die "$PROPOSALS_TS not found. Run from the Positron repo root, or use --app or --positron-version."
positron_proposals=$(resolve_proposals_from_source "$PROPOSALS_TS")
proposals_label="$PROPOSALS_TS"
fi
proposal_count=$(echo "$positron_proposals" | wc -l | tr -d ' ')
if [[ "$VERBOSE" == true ]]; then
echo "Positron proposals ($proposal_count versioned, from $proposals_label):"
echo "$positron_proposals" | sed 's/^/ /'
else
echo "Positron proposals: $proposal_count versioned (from $proposals_label)"
fi
echo ""
if [[ -n "$TAG_PREFIX" ]]; then
# Try to get Code OSS version for per-tag engine checking
if [[ -z "$_CODE_OSS_MINOR" && -f "package.json" ]]; then
local_version=$(jq -r '.version' package.json 2>/dev/null) || true
_CODE_OSS_MINOR=$(echo "$local_version" | cut -d. -f2)
fi
# Explicit tag prefix -- check just that series
check_series "$TAG_PREFIX" "$positron_proposals"
else
# Determine Code OSS version (if not already set by --positron-version)
if [[ -z "$_CODE_OSS_MINOR" ]]; then
if [[ -f "package.json" ]]; then
code_oss_version=$(jq -r '.version' package.json)
else
die "No package.json found. Run from the Positron repo root, use --positron-version, or use --tag-series."
fi
_CODE_OSS_MINOR=$(echo "$code_oss_version" | cut -d. -f2)
echo "Code OSS version: $code_oss_version"
fi
discover_tag_series "$code_oss_version"
[[ -n "$_CANDIDATES" ]] || die "No compatible tag series found for Code OSS $code_oss_version"
for series in $_CANDIDATES; do
check_series "$series" "$positron_proposals"
# Stop checking lower series once we find a compatible release.
# Pre-releases alone don't stop the search -- we prefer releases.
if [[ -n "$_LATEST_OK" ]]; then
break
fi
done
fi
# --- Summary ------------------------------------------------------------------
echo ""
if [[ -n "$_LATEST_OK" ]]; then
echo "Latest compatible release: $_LATEST_OK"
if [[ -n "$_LATEST_PRERELEASE" ]]; then
echo "Latest compatible pre-release: $_LATEST_PRERELEASE"
fi
elif [[ -n "$_LATEST_PRERELEASE" ]]; then
echo "Latest compatible (pre-release only): $_LATEST_PRERELEASE"
else
echo "No compatible tags found."
fi
Related skills
FAQ
What does pick-copilot-tag do?
pick-copilot-tag is a Claude Code skill for ai & agent building.
When should I use pick-copilot-tag?
When you need to helps with ai & agent building tasks during AI-assisted development., or when pick-copilot-tag is a claude code skill for ai & agent building.
What are the main capabilities?
pick-copilot-tag; AI & Agent Building; AI-coding skill.