Claude.app minified source inspection
Yes. I found the installed app at /Applications/Claude.app rather than ~/Applications/Claude.app.
What’s in the bundle
It is an Electron app:
- Bundle ID:
com.anthropic.claudefordesktop - Version:
1.14271.0 - Main archive:
/Applications/Claude.app/Contents/Resources/app.asar - Web app assets:
/Applications/Claude.app/Contents/Resources/ion-dist
Is minified source available?
Yes, there is inspectable bundled JavaScript:
Electron desktop app code inside
app.asarapp.asarcontains Vite-built JS under:.vite/build/index.js.vite/build/index.pre.js.vite/build/mainWindow.js.vite/build/mainView.js.vite/build/quickWindow.js- renderer HTML/JS under
.vite/renderer/...
- I extracted it briefly to
/tmpand confirmed the JS is present and minified/bundled. - The archive also contains
package.json, native modules, and some normal npm dependency source likewsandnode-pty.
Claude web UI assets outside the ASAR
/Applications/Claude.app/Contents/Resources/ion-dist/assets/v1- I counted 723 JS files, totaling about 50 MB.
- Main entry appears to be:
/Applications/Claude.app/Contents/Resources/ion-dist/assets/v1/index-CD05FcCU.js
- Largest chunk is ~7.1 MB.
Are source maps included?
Mostly no.
ion-disthas 0.mapfiles, and the inspected chunks did not includesourceMappingURLcomments.app.asarhas 0.mapfiles.- Some
.vite/build/*.jsfiles do contain comments like:
//# sourceMappingURL=index.js.map
…but the corresponding .map files are not present in the ASAR. So browser/devtools won’t recover original TypeScript/React source from local sourcemaps.
Bottom line
There is plenty of bundled/minified JavaScript available to inspect and beautify, but not original source with sourcemaps. We can still use tools like prettier, esbuild, terser formatting, or AST search to make specific chunks readable, but symbol names are often mangled and module boundaries are mostly lost.
Found it: skills-plugin is a managed cache
In app.asar, the relevant code is a minified class logged as [SkillsPlugin]. It defines:
MF = "local-agent-mode-sessions"Cxr = "skills-plugin"E3 = "skills"- Base dir:
app.getPath("userData") / local-agent-mode-sessions / skills-plugin - Per-account/org plugin dir:
~/Library/Application Support/Claude/local-agent-mode-sessions/skills-plugin/<orgId>/<accountId>
On your machine I confirmed that exists at e.g. the Claude skills-plugin cache.
When it gets overwritten
1. On app/session-manager startup
LocalAgentModeSessionManager.onInitialized(...) calls:
qu.startPeriodicSync()
qu is the singleton new SkillsPlugin.
startPeriodicSync() immediately calls:
this.periodicSync()
So the cache is rewritten shortly after the app initializes with account/org context.
2. Every periodic sync interval
Default interval is:
V1e = 600000 // 10 minutes
It can be overridden by a feature/config value:
skillsSyncIntervalMs
Periodic sync only runs while the window is focused:
if (!windowFocused) skip
3. On window focus after the interval has elapsed
There is a focus handler:
if (Date.now() - lastPollTime >= syncIntervalMs) periodicSync()
So focusing Claude after ~10+ minutes can trigger another overwrite/sync.
4. When the web UI calls LocalAgentModeSessions.syncSkills
The IPC interface exposes:
LocalAgentModeSessions.syncSkills
It calls:
qu.triggerSync()
triggerSync() waits 5 seconds, then runs periodicSync().
What exactly gets overwritten
Built-in Anthropic skills are rewritten every sync
Every sync calls:
ensurePluginStructure(pluginDir)
_writeBuiltInSkillsTo(pluginDir)
For each built-in skill, _writeOneBuiltInSkill() does:
Resolve:
<pluginDir>/skills/<skill-name>/SKILL.mdIf the skill directory exists and contains anything other than a single
SKILL.md, it deletes the entire skill directory:rm(skillDir, { recursive: true, force: true })It then writes a fresh
SKILL.md:writeFile(skillDir/SKILL.md, generatedFrontmatter + prompt)
So edits to built-in cached skills like schedule, consolidate-memory, setup-cowork, etc. will be overwritten on every sync. Extra files in those dirs cause the whole directory to be reset.
Remote/server skills are overwritten when changed or missing
It fetches enabled skills from:
/api/organizations/<org>/skills/list-skills?include_wiggle_skills=true&entrypoint=local-agent
Then downloads contents via:
/api/organizations/<org>/skills/download-dot-skill-file?skill_id=...&entrypoint=local-agent
A remote skill is re-downloaded when:
- it is not in
manifest.json updatedAtdiffers from the manifest- its local
SKILL.mdis missing
Removed remote skills are deleted from disk.
User-created local skills are protected from sync overwrite
Local skills saved through the app are stored in the same plugin dir but marked:
creatorType: "user"
syncManaged: false
The sync logic explicitly preserves syncManaged === false skills and avoids overwriting remote/built-in conflicts with them.
However, if saveLocalSkill(name, ..., overwrite=true) is called, it directly replaces that skill’s SKILL.md. Other files in the user skill directory are kept.
Important practical conclusion
Treat:
~/Library/Application Support/Claude/local-agent-mode-sessions/skills-plugin/...
as a generated cache, not a stable authoring location.
Manual edits there are likely to disappear:
- built-in skills: on every sync/start/focus-triggered poll
- remote skills: whenever server
updatedAtchanges,SKILL.mdis missing, or sync cleans orphans - user skills: only via explicit local save/delete/enable actions, unless their manifest entry is damaged/lost
I also found a clearCache() / clearPluginDir() method that would delete the whole active skills-plugin dir, but in the source paths I checked, I didn’t find an obvious normal caller for it.
No — they’re not public in the “unauthenticated internet API” sense.
They appear to be Claude web/app backend endpoints on the logged-in Claude origin, scoped to your active org:
GET /api/organizations/<org_uuid>/skills/list-skills?include_wiggle_skills=true&entrypoint=local-agent
GET /api/organizations/<org_uuid>/skills/download-dot-skill-file?skill_id=<skill_id>&entrypoint=local-agent
From the desktop code:
- It first resolves the active org via local auth/session state.
- It calls these through the app’s authenticated network layer.
- The URLs include an organization UUID.
- The data returned is specifically the user/org’s enabled skills.
- Download uses a
skill_id, also under the org route.
So they’re best understood as private, authenticated, undocumented Claude app APIs. If you call them without the Claude session cookies / app auth context, I’d expect 401, 403, or a redirect/login-style response. If called with a logged-in Claude browser/app session, they may work, but that’s using your authenticated account context, not public access.
Also: since these are internal/undocumented endpoints, they can change or disappear without notice.
No — I found official documentation for Skills, but not for the Claude Desktop/claude.ai internal endpoints we saw in the app bundle.
Documented public API endpoints are under Anthropic’s API host:
https://api.anthropic.com/v1/skills
https://api.anthropic.com/v1/files
The official API overview lists Skills API as:
POST /v1/skills
GET /v1/skills
See Anthropic’s API overview and Using Agent Skills with the API.
The desktop app endpoints we found are different:
/api/organizations/<org_uuid>/skills/list-skills?include_wiggle_skills=true&entrypoint=local-agent
/api/organizations/<org_uuid>/skills/download-dot-skill-file?skill_id=<skill_id>&entrypoint=local-agent
I did not find those documented in Anthropic’s public Skills/API docs. The public docs describe:
- API skill management via
/v1/skills - API use via
container.skills - claude.ai custom skills through Settings / UI
- Claude Code skills as filesystem-based
The docs also explicitly note that skill surfaces are separate: skills uploaded to claude.ai, the API, and Claude Code do not automatically sync across surfaces. That supports the idea that the Claude Desktop endpoints are internal claude.ai/Desktop sync endpoints, not the public Skills API.
So: documented public API: yes, /v1/skills; the specific /api/organizations/.../skills/... endpoints: apparently undocumented/internal.