Skip to content
Back to skills

Update

ASecurity

For claude-desktop-extra - handle a new upstream Claude Desktop version end-to-end: build, fix failing patches, diff old vs new JS for new platform gates, audit feature flags + ion-dist + platform gates, update baseline docs + CHANGELOG, bump .upstream-version, then commit.

  • 656 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added August 31, 2026
ai-agentsgobashnoderailsgitapibackend

Works with

  • claude code
  • claude desktop
  • api
  • mcp

Security analysis

A93/100
  • highPerforms destructive filesystem operations

Pro shows the line behind each finding and how to fix it

Scanned September 26, 2026

npx -y skills add patrickjaja/claude-desktop-extra --skill update --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Update?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Update
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/patrickjaja-update/badge)](https://www.skillsdirectory.com/skills/patrickjaja-update)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: update
description: For claude-desktop-extra - handle a new upstream Claude Desktop version end-to-end: build, fix failing patches, diff old vs new JS for new platform gates, audit feature flags + ion-dist + platform gates, update baseline docs + CHANGELOG, bump .upstream-version, then commit.
disable-model-invocation: true
---

# Update to a new upstream Claude Desktop version

**When to run this:** normally you don't. CI auto-releases new upstream versions (version-check.yml dispatches build-and-release.yml; green run = released + `.upstream-version` bumped + tracking issue closed). Run this skill when the **auto-release failed** (a comment on the "new version detected" issue links the failed run) or when you want a deep audit of a bump. On a patch failure, decide FIRST: did the re-minify just move the anchor (fix the regex), or did upstream natively implement what we patch (**remove the patch** - the expected direction, since Anthropic maintains 1p Linux support)?

Run from the repo root. The official Linux `.deb` is remotely managed and re-minifies every release; patches use `[\w$]+` wildcards on stable string anchors. Step 1 runs `/fresh-upstream` for a clean extract; Step 9 ends with `/deploy` to release. `$ARGUMENTS` may name a target version.

Use sequential thinking and delegate independent analysis (diff, flag audit, ion-dist, platform gates) to parallel sub-agents where useful; you coordinate and edit.

## Search rules (apply to every step)
- The main bundle is code-split since v1.19367.0: `index.js` is a loader stub, the code lives in `index.chunk-<hash>.js` siblings (hashes change every release) + `index.pre.js`. For any "search the bundle" command, use a concatenation per side:
  ```bash
  B=./tmp/app.asar.contents/.vite/build
  cat $B/index.pre.js $B/index.js $B/index*.chunk-*.js > ./tmp/new-bundle.js   # same for the OLD extract -> ./tmp/old-bundle.js
  ```
- Use `grep -a` on extracted bundles. `rg -a --no-ignore` silently fails on them (raw NUL bytes); a zero-hit `rg` is not evidence.
- Match JS identifiers with `[\w$]+`, never bare `\w+` - minified names contain `$` (`F$e`, `$S`) and `\w+` silently misses them.
- Since v1.12603.0 the bundle embeds **two** copies of `@anthropic-ai/claude-agent-sdk` (`grep -ao 'CLAUDE_AGENT_SDK_VERSION="[0-9.]*"' ./tmp/new-bundle.js | sort | uniq -c`). A pattern on SDK-internal code matches twice: decide explicitly whether to patch both copies and assert the count.

## Step 0 - clean slate
```bash
cd "$(git rev-parse --show-toplevel)"
git status                  # must be clean before starting
rm -rf build/ extract/      # old artifacts
```
Note current `.upstream-version`. If you're here because the auto-release failed, read the failed run's log first - it names exactly which patch (and which sub-patch counter) failed.

## Step 1 - build & fix patches
Run the build for this OS (Arch here). It auto-downloads the latest official `.deb`, applies patches, packages:
```bash
./scripts/build-local.sh
# Ubuntu/Debian: SKIP_SMOKE_TEST=1 ./scripts/build-ubuntu-local.sh
# Fedora/RHEL:   ./scripts/build-fedora-local.sh
# Specific version / local .deb: --version 1.17282.0 | --deb /path/to/claude-desktop_amd64.deb
```
If patches fail (upstream renamed identifiers / refactored / removed a feature):
1. Get a clean unpatched extract (run `/fresh-upstream`, or it's already in `./tmp/app.asar.contents/.vite/build/`). `./scripts/validate-patches.sh ./tmp/app.asar.contents` runs every patch against it and lists the failures.
2. For each failing patch, find the new pattern with `grep -ao '.{0,50}anchor.{0,50}'`, then fix `patches/<group>/<name>.nim` with capture/replace, reusing the captured names:
   ```nim
   # BAD - hardcoded minified names break on the next release
   let pattern = re2"function pTe\(\)\{const t=ce\.screen\.getPrimaryDisplay\(\)"
   # GOOD - wildcard + capture, rebuild from the captured groups
   let pattern = re2"(function [\w$]+\(\)\{const t=)([\w$]+)(\.screen\.)getPrimaryDisplay\(\)"
   ```
   **Edit the `.js` in `js/`** for Computer Use / cowork-font and other `staticRead` patches, then `touch` the `.nim` (the Makefile tracks most but not all `staticRead` deps).
3. Recompile + test one patch against the stub+chunks concatenation (what the orchestrator stages):
   ```bash
   cd patches && make <patch_name> && cd ..
   B=./tmp/app.asar.contents/.vite/build
   { cat $B/index.js; for c in $B/index.chunk-*.js; do printf '\n/*__CDB_SPLIT__%s__*/\n' "$(basename $c)"; cat "$c"; done; } > ./tmp/test-index.js
   patches/<group>/<patch_name> ./tmp/test-index.js; echo "exit=$?"
   ```
   The staged concatenation never passes `node --check` as a whole; the per-chunk `node --check` in the build is authoritative. A syntax error there means the patch replaced only part of a construct.
4. Re-run the build until all patches pass. **Every sub-patch must succeed or `quit(1)`** - never `[WARN]`+continue. If a feature was upstreamed, **remove the patch** (`git rm`, bump `EXPECTED_PATCH_COUNT` in `scripts/apply_patches.py`). The absorption probe (`scripts/check-upstream-absorbed.py`, run by the build) flags ABSORBED/PARTIAL patches: audit that upstream ships the same behavior on Linux, then remove. FAILED means re-fit, not remove. See AGENTS.md Rules 4/6.

## Step 2 - Linux-compat analysis (new gates?)
Diff old vs new for newly darwin/win32-gated features that need Linux support (`OLD`/`NEW` = the two concatenations from the search rules):
```bash
diff <(grep -aoE '.{0,40}process\.platform.{0,40}' "$OLD"|sort -u) <(grep -aoE '.{0,40}process\.platform.{0,40}' "$NEW"|sort -u)
diff <(grep -aoE '.{0,80}status:"unavailable".{0,80}' "$OLD"|sort -u) <(grep -aoE '.{0,80}status:"unavailable".{0,80}' "$NEW"|sort -u)
diff <(grep -aoE 'require\("[^"]+"\)' "$OLD"|sort -u) <(grep -aoE 'require\("[^"]+"\)' "$NEW"|sort -u)   # new native modules -> need x86_64+aarch64
```
Validate any new input/screenshot feature across all 5 session types (X11, wlroots, GNOME, KDE, XWayland).

## Step 3 - diff old vs new JS
```bash
diff <(cd ./tmp/app.asar.contents-OLD && find . -type f | sed 's/-[A-Za-z0-9_-]\{8\}\.js$/.js/' | sort) \
     <(cd ./tmp/app.asar.contents && find . -type f | sed 's/-[A-Za-z0-9_-]\{8\}\.js$/.js/' | sort)   # new/removed files
diff <(grep -aoE 'handle\("[^"]+"' "$OLD"|sort -u) <(grep -aoE 'handle\("[^"]+"' "$NEW"|sort -u)      # IPC handlers
```
Also skim Claude Code / Cowork subsystem changes. Classify each finding: rename-only (no action) / new feature (may need a Linux patch) / changed behavior (existing patches may break) / removed (clean up patches/docs).

## Step 4 - feature-flag audit
Read `baseline/CLAUDE_FEATURE_FLAGS.md`. Find the new static-registry function name (changes every release; anchor on a known flag like `ccdPlugins`). Diff flag sets:
```bash
diff <(grep -aoE '[\w$]+\("[0-9]{6,}"\)' "$OLD"|sort -u) <(grep -aoE '[\w$]+\("[0-9]{6,}"\)' "$NEW"|sort -u)
```
Check `enable_local_agent_mode.nim`'s override list still covers the cowork/code flags and its Zod schema includes them. Update the doc + version-history table.

Also refresh the flag catalog in `js/growthbook_overrides.js` (TEMPLATE): it lists every store-consulted flag of the audited version, commented out. Extract IDs with `rg -o '[\w$]+(?:\.[\w$]+)*\("([0-9]{6,10})"[,)]' -r '$1' <new-bundle-concat> | sort -u`, drop the IDs force-rewritten by patches (`rg -oI '"[0-9]{6,10}"' patches/*/*.nim`, minus IDs only mentioned in comments), and update descriptions + the version stamp in the header. Then regenerate the browsable copy and rebuild the binary:
```bash
bash scripts/check-jsonc-template-sync.sh --write   # updates docs/claude-desktop-extra.jsonc
touch patches/core/add_growthbook_overrides.nim && (cd patches && make)
```
CI runs `scripts/check-jsonc-template-sync.sh` (no `--write`) and fails if the docs catalog drifts from the shipped template.

## Step 5 - ion-dist SPA audit
Read `baseline/ION.md`. ion-dist is in the `.deb`'s resources, not inside `app.asar`:
```bash
ION=./tmp/extract/usr/lib/claude-desktop/resources/ion-dist
ls "$ION/index.html" && du -sh "$ION" && find "$ION" -name '*.js' | wc -l   # vs baseline: big swing = refactor
grep -l 'org-plugins' "$ION/assets/v1/"*.js                                  # config chunk (hash changes every release)
grep -aoE 'mountPath:\{.{0,200}\}' "$ION/assets/v1/"*.js                     # a linux key here = maybe upstreamed
grep -aoE '/Library/Application Support.{0,60}|%ProgramFiles%.{0,60}' "$ION/assets/v1/"*.js
```
`fix_ion_dist_linux.nim` finds its target by content signature, not filename. Update `ION.md` / the patch if anything moved.

## Step 6 - platform-gate re-audit
Read `baseline/PLATFORM_GATE_BASELINE.md` first; only gates that don't map to an existing row matter.
```bash
for p in darwin win32 linux; do echo "$p: $(grep -ao "platform===\"$p\"" "$NEW" | wc -l)"; done   # vs baseline counts
grep -aoE '.{0,60}process\.platform==="(darwin|win32)".{0,80}' "$NEW" | sort -u
grep -aoE '.{0,80}!=="darwin".{0,40}!=="win32".{0,80}' "$NEW" | sort -u
```
Classify each: PATCHED (maps to a patch) / NATIVE (real Apple/Win API) / STUB (disabled on all platforms) / **PORTABLE** (mac/win-only, no native dep, not patched - the only actionable class). **Verify before reporting:** trace every PORTABLE candidate yourself and quote the verbatim snippet; past sub-agent audits hallucinated removed features and fake UUIDs. Update the baseline's `Last audited`, counts and rows.

## Step 7 - Cowork backend
Cowork runs on the `.deb`'s bundled native VM backend (cowork-linux-helper + virtiofsd + smol-bin + QEMU/OVMF; requires `/dev/kvm`). Nothing to update on a bump.

## Step 8 - docs
Update only what changed:
- `CHANGELOG.md` - add the new entry (one `##` section per day, newest at top; informative not a debug log).
- `baseline/CLAUDE_FEATURE_FLAGS.md`, `CLAUDE_BUILT_IN_MCP.md` (check `registerInternalMcpServer` calls), `ION.md`, `PLATFORM_GATE_BASELINE.md` - if their tracked internals moved.
- `docs/patches.md` patch tables - if patches added/removed/changed; the README's summary carries the per-directory counts. **Do NOT touch README install-command version numbers** (CI updates those via `sed`; manual edits cause merge conflicts).

## Step 9 - bump .upstream-version (required) + commit
```bash
echo "<NEW_VERSION>" > .upstream-version    # closes the "new version detected" issue, greens the README badge
```
Then commit + push to `master` directly, only when the user says to. After merge, release with `/deploy` (or `/deploy force` for patch-only changes where upstream version didn't move).

## Guardrails
- Always re-extract fresh if `./tmp` is stale (different minified names -> wrong conclusions).
- A green build with all patches applied + docs synced + `.upstream-version` bumped is "done". Don't claim done with failing patches.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.