
Launch
Start an isolated VS Code OSS (Code from sources) instance with working Copilot auth, unique debug ports, and optional agent-host mode for extension development.
Install
npx skills add https://github.com/microsoft/vscode --skill launchWhat is this skill?
- Slim authenticated user-data-dir copy preserves GitHub/Copilot auth while dropping caches
- Isolated --shared-data-dir prevents colliding with other OSS instances
- Assigns unique CDP, extension host, main, and agent host debug ports
- Emits one JSON line to stdout with ports and paths for programmatic callers
- --agents flag and --clone-extensions / --full profile modes for speed vs fidelity
Adoption & trust: 199 installs on skills.sh; 186k GitHub stars; 3/3 security scanners passed (skills.sh audits).
Recommended Skills
Journey fit
Building editor extensions and agent features against Code OSS is core build-time agent-tooling work for VS Code contributors. Agent-tooling subphase fits launching instrumented dev instances with CDP, extension host, and agent host ports for iterative coding.
Common Questions / FAQ
Is Launch safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.
SKILL.md
READMESKILL.md - Launch
#!/usr/bin/env bash # Launch Code OSS (VS Code from sources) with: # - a fresh, slimmed copy of the authenticated user-data-dir (so Copilot/GitHub auth works) # - an isolated --shared-data-dir (otherwise two instances share ~/.vscode-oss-shared and crash each other) # - unique debug ports for renderer (CDP), extension host, main process, and agent host # # Auth on macOS comes from the OS keychain (per-app, shared automatically) plus # the encrypted blob in User/globalStorage/state.vscdb (per-UDD). The slim copy # keeps the auth-relevant state and drops caches / workspaceStorage / logs. # # Prints a single JSON line to stdout with the chosen ports + paths so the # caller can pick them up programmatically. Logs go to stderr. # # Usage: # launch.sh [--agents] [--source-user-data-dir <path>] [--repo <vscode-repo-root>] # [--clone-extensions] [--full] [-- <extra code.sh args>] # # Flags: # --clone-extensions Copy the source extensions/ into the new profile (~10s). # Default: start with an EMPTY extensions/ dir - fastest # and conflict-free, but no third-party extensions. # --full Copy the entire profile (incl. extensions). Use if the # slim copy is missing something you need. # # Defaults: # --source-user-data-dir $CODE_OSS_DEV_AUTHED_USER_DATA_DIR (else ~/.vscode-oss-dev) # --repo $PWD if it looks like a vscode checkout; otherwise pass it explicitly set -euo pipefail umask 077 AGENTS=0 SOURCE_UDD="${CODE_OSS_DEV_AUTHED_USER_DATA_DIR:-$HOME/.vscode-oss-dev}" REPO="" EXTRA_ARGS=() CLONE_EXTENSIONS=0 FULL=0 while [[ $# -gt 0 ]]; do case "$1" in --agents) AGENTS=1; shift ;; --source-user-data-dir) SOURCE_UDD="$2"; shift 2 ;; --repo) REPO="$2"; shift 2 ;; --clone-extensions|--copy-extensions) CLONE_EXTENSIONS=1; shift ;; --full) FULL=1; shift ;; --) shift; EXTRA_ARGS=("$@"); break ;; *) echo "Unknown arg: $1" >&2; exit 2 ;; esac done if [[ -z "$REPO" ]]; then if [[ -x "$PWD/scripts/code.sh" ]]; then REPO="$PWD" else echo "Could not find a vscode checkout in $PWD. Pass --repo <path>." >&2 exit 2 fi fi if [[ ! -d "$SOURCE_UDD" ]]; then echo "Source user-data-dir does not exist: $SOURCE_UDD" >&2 echo "Pass --source-user-data-dir <path> or set CODE_OSS_DEV_AUTHED_USER_DATA_DIR." >&2 exit 2 fi pick_port() { node -e ' const net = require("net"); const s = net.createServer(); s.listen(0, "127.0.0.1", () => { const p = s.address().port; s.close(() => console.log(p)); }); ' } CDP_PORT=$(pick_port) EXTHOST_PORT=$(pick_port) MAIN_PORT=$(pick_port) AGENTHOST_PORT=$(pick_port) STAMP=$(date +%Y%m%d-%H%M%S)-$$ RUN_DIR="${TMPDIR:-/tmp}/code-oss-dev/$STAMP" DEST_UDD="$RUN_DIR/user-data" SHARED_DATA_DIR="$RUN_DIR/shared-data" mkdir -p "$DEST_UDD" "$SHARED_DATA_DIR" # Excludes (deny-list, so future VS Code additions copy through by default). # Anchored excludes (starting with /) match only at the top level so we don't # accidentally strip files inside subdirs that share a name. EXCLUDES=( '/extensions' # handled separately below '/workspaceStorage' 'User/workspaceStorage' # per-workspace state, incl. chat sessions 'User/History' # local file edit history '/CachedExtensionVSIXs' # backup VSIXs '/logs' '/Cache' '/Code Cache' '/CachedData' '/component_crx_cache' '/GPUCache' '/ShaderCache' '/Dawn*Cache' '/Backups' '/blob_storage' '/BrowserMetrics' '/Crashpad' '/Session Storage' '/Singleton*' '*.lock' '*.sock' ) if [[ "$FULL" == "1" ]]; then echo "[launch.sh] full copy: $SOURCE_UDD -> $DEST_UDD" >&2 rsync -a "$SOURCE_UDD/" "$DEST_UDD/" else echo "[launch.sh] slim copy: $SOURCE_UDD -> $DEST_UDD" >&2 RSYNC_ARGS=(-a) for e in "${EXCLUDES[@]}"; do RSYNC_ARGS+=(--exclude="$e"); done rsync "${RSYNC_ARGS[@]}" "$SOURCE_UDD/" "$DEST_UDD/" fi # Extensions: # --full