Development
#ai
launch
Launch Code OSS (VS Code from sources) into an isolated throwaway profile with unique debug ports so you can drive it with @playwright/cli AND attach a Node debugger via dap-cli in the same session. Use when working on VS Code itself and you want to interact with the running workbench, automate chat or UI flows, test UI features, take screenshots, set breakpoints in the renderer / extension host / main process, or combine UI driving with debugging.
DeepseekModel
Curated skill
★ Featured
Quality Excellent · 90
v1.0.0
Get
https://deepseekmodel.com/api/download.php?id=microsoft-vscode-agents-skills-launch-skill-md&format=skill
Download .skill
Standard format with system_prompt and model_config, ready for any agent framework
The actual content of the system_prompt field in the .skill file.
name launch description Launch Code OSS (VS Code from sources) into an isolated throwaway profile with unique debug ports so you can drive it with @playwright/cli AND attach a Node debugger via dap-cli in the same session. Use when working on VS Code itself and you want to interact with the running workbench, automate chat or UI flows, test UI features, take screenshots, set breakpoints in the renderer / extension host / main process, or combine UI driving with debugging. Code OSS Dev - Launch + Debug You're working on VS Code itself and you want to: Launch a Code OSS build from sources that is already signed in (Copilot, GitHub, etc.) so chat / agent flows work end-to-end. Drive it with @playwright/cli over CDP (UI automation). Optionally attach a debugger via dap-cli to set breakpoints in the renderer, extension host, or main process. Run multiple instances at once without port conflicts. This skill provides a launcher that clones an authenticated user-data-dir to a throwaway temp folder, picks free ports for every debug surface, and prints them as JSON so you can pick them up programmatically. The clone is slim : workspace storage, browser caches, file history, cached VSIX backups, and old logs are excluded by default. On macOS, auth tokens live in the OS keychain plus small files inside User/globalStorage - both of which are preserved. On Windows the GitHub session lives in the shared-data-dir instead, which the launcher seeds separately (see Windows authentication ). Prerequisites macOS, Linux, or Windows. macOS / Linux : the launcher is a bash script ( scripts/launch.sh ) and depends on rsync , nohup , and Node on PATH . The example caller snippets below also use jq (parse the JSON output) and lsof (kill-by-port fallback) — install those if you plan to use them, but the launcher itself does not require them. Windows : use scripts\launch.ps1 instead. It needs no extra tooling beyond Node on PATH , and works on both Windows PowerShell 5.1 and PowerShell 7+. jq is not needed — parse the JSON with ConvertFrom-Json . If Node is managed with fnm , put it on PATH first: fnm env --use-on-cd --shell powershell | Out-String | Invoke-Expression fnm use # picks up the repo's .nvmrc A VS Code checkout with node_modules/ installed ( npm install if missing — do not symlink from a sibling worktree; that breaks builds in subtle ways). A VS Code checkout with sources built. Run npm run compile once (one-shot) or npm run watch for incremental rebuilds. Both build the full client and all built-in extensions under extensions/ . You must build the full product to run successfully, building just the client is not enough. An authenticated Code OSS profile to seed from. By default the launcher uses ~/.vscode-oss-dev on macOS/Linux or $env:USERPROFILE\.vscode-oss-dev on Windows, which is the user-data-dir the repo's launch.json configs use - if the user has ever signed in to Copilot in a dev build, this should work. Only pass --source-user-data-dir <path> (or set $CODE_OSS_DEV_AUTHED_USER_DATA_DIR ) when you specifically want to seed from a different profile (e.g. your regular ~/Library/Application Support/Code install). If Code OSS launches and needs a sign-in, don't give up! Use the questions tool to ask the user to sign in. @playwright/cli available (it's a devDependency in the vscode repo - npm install then use npx @playwright/cli ). For debugger work: dap-cli on PATH . If debugger support would be useful but the dap-cli skill is not present, prompt the user to install it from https://github.com/roblourens/dap-cli . CSS selectors are internal implementation details. If a selector-based eval stops working, take a fresh snapshot , inspect the current DOM, and update the selector rather than assuming an old one still applies. The launcher copies the source profile to a temp dir and never mutates the original. Each launch gets its own isolated --user-data-dir and --extensions-dir . The launcher always sets files.simpleDialog.enable: true in the launched profile's User/settings.json . This is required for automation: VS Code's native OS file dialogs cannot be driven via @playwright/cli over CDP and are completely unreachable over SSH on headless macOS. The simple (quick-input) dialog can be navigated with press and clipboard paste. The override is per-launch and only affects throwaway profiles. Before launching from an agent session, call get_current_session and pass its title as --session-title . For a regular editor window, the launcher writes that title into the throwaway profile's window.title setting. For an Agents window, it passes the title to the Command Center. This never modifies the source profile. For unattended automation, pass --disable-workspace-trust so a trust dialog cannot block the flow or extension-host startup. The override is process-scoped and does not modify the source profile. Only use it with content you trust. Launch The launcher script lives next to this SKILL.md at scripts/launch.sh (macOS/Linux) or scripts\launch.ps1 (Windows). Resolve it relative to wherever this skill file is installed - do not hardcode an absolute path. # LAUNCH=<dir-of-this-SKILL.md>/scripts/launch.sh SESSION_TITLE=<title-from-get_current_session> " $LAUNCH " --session-title " $SESSION_TITLE " # default: workbench " $LAUNCH " --agents --session-title " $SESSION_TITLE " " $LAUNCH " -- <workspace-path> # forward extra args to code.sh " $LAUNCH " --source-user-data-dir <path> # pick a specific authed profile " $LAUNCH " --repo <vscode-repo-root> # if not run from the repo " $LAUNCH " --clone-extensions # start with a copy of the source extensions/ (~few seconds) " $LAUNCH " --full # skip slim excludes; copy everything " $LAUNCH " --skip-prelaunch # reuse already-current build outputs " $LAUNCH " --disable-workspace-trust # avoid trust prompts for trusted automation inputs On Windows, invoke the PowerShell launcher with the same flags: $skillDir = '<dir-of-this-SKILL.md>' $launch = Join-Path $skillDir 'scripts\launch.ps1' $sessionTitle = '<title-from-get_current_session>' & $launch --session-title $sessionTitle # default: workbench & $launch --agents --session-title $sessionTitle & $launch -- --use-mock-keychain # forward extra args to code.bat & $launch --source-user-data-dir C:\path\to\profile & $launch --repo C:\path\to\vscode & $launch --clone-extensions & $launch --full & $launch --skip-prelaunch & $launch --disable-workspace-trust If the local execution policy blocks scripts, invoke it with powershell -ExecutionPolicy Bypass -File <path-to-launch.ps1> . The Windows implementation has the same profile isolation, slim-copy excludes, settings merge, port allocation, foreground pre-launch, and CDP-ready contract as the bash launcher; only the shell commands and path syntax differ. What gets copied (slim mode, the default) The exclude list mirrors the one used by VS Code's own perf-test skill ( .github/skills/auto-perf-optimize ), which is known to keep Copilot auth and language-model availability working. Specifically WebStorage/ , Service Worker/ , Local Storage/ , Cookies , Network Persistent State , TransportSecurity , Trust Tokens , Preferences , machineid , and the entire User/globalStorage/ (which holds state.vscdb ) are all preserved. Windows authentication Windows has no shared per-app keychain for these secrets, so they live in files on disk - but not all in the user-data-dir . The GitHub session is stored at StorageScope.APPLICATION_SHARED only on Windows (see useSharedStorage and CROSS_APP_SHARED_SECRET_KEYS in src/vs/platform/secrets/common/secrets.ts ), which puts the two halves of the credential in different directories : Piece Location Encrypted GitHub session blob <shared-data-dir>/sharedStorage/state.vscdb DPAPI-wrapped decryption key ( os_crypt.encrypted_key ) <user-data-dir>/Local State The launcher therefore seeds both : it copies the source profile and copies the source shared-data-dir into the run's throwaway shared-data dir. The source resolves the same way IEnvironmentService.appSharedDataHome does - $env:CODE_OSS_DEV_AUTHED_SHARED_DATA_DIR if set, else $env:VSCODE_PORTABLE\shared-data when running portable, else ~/<product.sharedDataFolderName> (i.e. %USERPROFILE%\.vscode-oss-shared ). It also verifies Local State , machineid , and Network survived the profile copy, and warns on stderr if neither database holds a GitHub session. This asymmetry is invisible on macOS/Linux, where the same token lands inside the profile. A Windows-only "always signed out" symptom is a shared-data-dir problem, not a profile problem: signing in against the source profile writes a perfectly good session, but before this seeding existed every launch handed Code OSS an empty shared dir and threw it away. To (re)establish the source session: run .\scripts\code.bat --user-data-dir=$env:USERPROFILE\.vscode-oss-dev directly, sign in once, and close it. That writes the blob to %USERPROFILE%\.vscode-oss-shared and the key to the profile's Local State ; later launches copy both and inherit the session. Profiles that predate the APPLICATION_SHARED migration can still hold the secret in User/globalStorage/state.vscdb . ApplicationSharedStorageMain registers application storage as a read fallback, so those profiles authenticate even with no shared-data-dir present - which is why a missing shared dir is reported as a fact rather than assumed fatal. Excluded (transient, regenerable, or known-not-needed): User/workspaceStorage/ - per-workspace state, including stored chat sessions (often multi-GB) User/History/ - local file edit history CachedExtensionVSIXs - backup VSIXs (hundreds of MB) logs Chromium caches at the profile root: Cache , Code Cache , CachedData , GPUCache , ShaderCache , Dawn*Cache , component_crx_cache ; and under the persistent integrated-browser partition: Cache , Code Cache , GPUCache , Dawn*Cache Backups , blob_storage , BrowserMetrics , Crashpad , Session Storage Singleton* , *.lock , *.sock (would conflict with the source instance) The persistent integrated-browser partition keeps website state such as cookies, local and session storage, IndexedDB, WebStorage, service workers, and preferences; only its regenerable caches are excluded. extensions/ defaults to a fresh empty directory - fastest and conflict-free, but the launched instance starts with no third-party extensions installed. Pass --clone-extensions to copy the source extensions dir into the temp profile so the new instance is independent of the source. Pass --full to skip all excludes if you suspect the slim copy is missing something you need. Why never share the source extensions/ dir directly? The extension management service writes a shared .obsolete file; two concurrent writers crash each other's shared background process. The launcher always uses an isolated extensions dir for the same reason it uses --shared-data-dir (see below). If the launched window says "language model unavailable" or otherwise looks unauthed, ask the user to sign in. The script runs pre-launch (electron download, compile-if-missing, built-in extensions) in the foreground , then starts Code OSS detached and blocks until the renderer's CDP endpoint is responding (up to ~90s) before printing the JSON line on stdout. If anything fails — preLaunch errors, code.sh exits early, CDP never opens — the script exits non-zero and dumps the relevant log tail to stderr. For repeated launches of the same prepared build, pass --skip-prelaunch after one successful normal launch. Only use it while a watch task keeps all output current or neither sources nor build outputs have changed; otherwise the new instance may run stale or incomplete code. { "pid" : 12345 , "cdpPort" : 53111 , "extHostPort" : 53112 , "mainPort" : 53113 , "agentHostPort" : 53114 , "userDataDir" : ".../user-data" , "extensionsDir" : ".../extensions" , "sharedDataDir" : ".../shared-data" , "runDir" : "..." , "logFile" : ".../code.log" , "repo" : "..." , "agents" : false , "timings" : { "profileMs" : 231 , "preLaunchMs" : 251 , "cdpReadyMs" : 459 , "totalMs" : 941 } } The additive timings object uses monotonic elapsed time to identify time spent preparing the isolated profile, running pre-launch, and starting Code OSS through CDP readiness. totalMs covers the complete launcher operation through readiness. Capture it with jq — no retry loop needed, CDP is already up when the JSON is printed: INFO=$( " $LAUNCH " | tail -n1) CDP=$(jq -r .cdpPort <<< " $INFO " ) EXT=$(jq -r .extHostPort <<< " $INFO " ) MAIN=$(jq -r .mainPort <<< " $INFO " ) AGENT=$(jq -r .agentHostPort <<< " $INFO " ) LOG=$(jq -r .logFile <<< " $INFO " ) PID=$(jq -r .pid <<< " $INFO " ) On Windows, capture and parse the JSON without jq : $info = & $launch | Select-Object -Last 1 | ConvertFrom-Json $cdp = $info.cdpPort $ext = $info.extHostPort $main = $info.mainPort $agent = $info.agentHostPort $log = $info.logFile $pid = $info.pid What each port is for Port Process Use with cdpPort ( --remote-debugging-port ) Renderer (the workbench window) @playwright/cli over CDP, also Chrome DevTools extHostPort ( --inspect-extensions ) Extension host (Node) dap-cli (Node inspector protocol) mainPort ( --inspect ) Electron main process (Node) dap-cli (Node inspector protocol) agentHostPort ( --inspect-agenthost ) Agent host process (Node) dap-cli (Node inspector protocol) Drive the UI with @playwright/cli Use the dynamic cdpPort from the launch JSON. The normal loop is: attach, confirm the target, snapshot, interact, then re-snapshot after meaningful UI changes. If you are unsure about Playwright CLI syntax, run npx @playwright/cli --help or npx @playwright/cli <command> --help instead of guessing option names. Always pick a unique PW_SESSION name and pass it as -s=$PW_SESSION on every npx @playwright/cli ... call. The CLI is backed by a persistent daemon ( cliDaemon.js ) keyed by session name; if two shells both omit -s= , they share the implicit "default" session and the most-recently-attached CDP "wins" for every subsequent command from either shell. The launch skill is built around isolation (per-instance UDD, ports, shared-data-dir), and this pattern keeps that isolation intact at the Playwright-driving layer too. A note on the alternative PLAYWRIGHT_CLI_SESSION env var: it's documented in the package README and works correctly for open -style workflows, but it interacts poorly with attach --cdp=... (the daemon ends up with both --cdp=... and --endpoint=<env-value> , and the latter wins, causing a connect ENOENT failure). Confirmed against @playwright/cli@0.1.13 . Explicit -s=NAME works in all modes. # At the top of your script / subagent prompt: PW_SESSION= "my-uniq-$$" # any unique string; $$ is fine for one shell per agent # launch.sh blocks until CDP is ready, so a single attach is enough. npx @playwright/cli -s= $PW_SESSION attach --cdp=http://127.0.0.1: $CDP npx @playwright/cli -s= $PW_SESSION tab-list npx @playwright/cli -s= $PW_SESSION snapshot After attach , later @playwright/cli commands keep using the connected app until you close or reattach — as long as you keep passing the same -s=$PW_SESSION . Selecting the right Electron target Electron apps can expose multiple windows or webviews. If tab-list shows about:blank , a webview, or otherwise the wrong target, switch targets before interacting: npx @playwright/cli -s= $PW_SESSION tab-list npx @playwright/cli -s= $PW_SESSION tab-select 2 npx @playwright/cli -s= $PW_SESSION snapshot If a target looks stale after relaunching, run npx @playwright/cli -s=$PW_SESSION close , attach again with $CDP , and re-check tab-list . Focusing the chat input Use the playwrightScripts/focus-chat-input.ts script in both the regular workbench and the Agents window. It performs the complete focus flow in one Playwright call: If a visible chat input is already focused, it does nothing. If a visible chat input exists but is not focused, it focuses that input.
Keywords that activate this skill. Click one to copy it.
This skill does not provide trigger words.
The downloaded .skill package contains the following fields.
| Field | Description |
|---|---|
| format | Format tag (skill/v1) |
| skill_id | Unique skill ID |
| name | Skill name |
| version | Version |
| description | Description |
| category | Categories (array) |
| trigger_words | Trigger words |
| tags | Tags |
| source | Source |
| source_url | Source URL (this page) |
| exported_at | Exported at (set per download) |
| system_prompt | System prompt body |
| model_config | Model config: provider / model / temperature / max_tokens / top_p |
| examples | Examples |
| install_guide | Import guide for Coze / Dify / Claude / custom frameworks |
The same skill can be exported in different platform formats.