Changelog

Every public release of AI SkillSafe, newest first.

This release reworks navigation across the app: a new sticky breadcrumb tells you exactly where you are at all times, and empty filter combos now point you at the closest non-empty broadening rather than just sitting blank.

  • Sticky breadcrumb (LocationHeader) at the top of every list pane. Artifacts views show tool › scope › type; Workbench shows Master › tool › category; Configs shows tool › scope. Scope / type / category segments are clickable to cycle filters in place. Tool and Master segments are read-only labels — no more dead-click buttons.
  • Smart empty-state guidance. When a filter combo yields zero items, the empty state surfaces up to three ranked broadening actions (“Switch to Codex (+2)”, “Show all scopes (+5)”, etc.) instead of just an empty pane. Backed by a pure computeFilterCounts derivation with unit tests and a useFilterCounts hook.
  • Workbench inventory warm-up. Cross-tool inventory is now scanned once on first mount so sidebar tool counts populate before you open the Workbench tab.
  • “Last backup …” line shown directly under the Configure & back up button, persisted across restarts via localStorage. The busy indicator stays on for at least 250ms (guarded against unmount mid-delay) so quick backups still register visually.
  • Sidebar a11y. Cloud and Backup toggle buttons announce Hide/Show state via dynamic aria-label.
  • i18n. “Settings” finalized as the canonical term (the brief “preferences” rename has been rolled back). Stub English nav-clarity strings removed from non-EN locales so missing translations show through honestly until they’re filled in.
  • Runtime safety. App degrades gracefully outside Tauri (web preview / tests) — no more crashes from unconditional @tauri-apps calls during module load.

This release adds a defense-in-depth security layer for installed skills, brings the canonical skillsafe.ai offline scanner into the app, and rounds out installation and debugging ergonomics.

  • Pre-install security shield. Downloaded bundles are now scanned against a signed rule feed before they land on disk. Block verdicts wipe the partial install; quarantine verdicts write a skillsafe.status frontmatter sentinel that survives reload/backup/sync and shows up in the artifact list as a safety badge. A Claude Code SessionStart hook can be installed that exits non-zero if any quarantined skill is present on disk.
  • Skills-Lock adapter. Canonical sorted, atomic-write lockfile plus detect/import for vercel, pcomans, and skillpm (pixi is YAML and detect-only). The Workbench surfaces a diff preview before applying an import.
  • MCP STDIO sanity-checker. Flags unpinned npx/uvx entries, blocklisted servers (from the feed), inline env secrets, and missing --sandbox on macOS Codex. The MCP editor shows the highest-severity finding per row.
  • Secrets-aware .env scrubber. New scanner pass + per-OS keychain rewriter (security on macOS, secret-tool on Linux, Get-StoredCredential on Windows). Rewritten files are marked with the same skillsafe.status sentinel so drift detection can tell.
  • Memory concatenation linter. Walks parent dirs (.git boundary, depth cap 5) and global memory files, merges by precedence with source markers, and surfaces contradictions — opposing always/never on similar subjects, conflicting model overrides — in the Workbench.
  • Offline scanner. Verbatim port of the canonical skillsafe.ai scanner: 12 passes covering prompt injection, secrets, shell threats, base64 deep-decode, Unicode obfuscation, structural mimicry, composite + surplus, and the full BOM. Surfaced as a per-row shield badge, a “Scan all” toolbar button, and an inline report panel in the bundle drawer.
  • Git-source install. Install directly from any GitHub repo via owner/repo[@ref][:subpath] or a full URL. Provenance (commit hash, pin flag) is recorded under ~/.skillsafe/git-sources.json for later drift detection. Capability allowlist expanded to api.github.com and codeload.github.com.
  • Trigger debugger. Free-text query → ranked matches with precedence and shadowing, plus near-duplicate conflict detection. Each artifact row now shows its on-disk bundle path (with $HOME collapsed to ~); the debugger shows the same path under each candidate so two same-name skills can be told apart.
  • Docs. Top-level README rewritten to reflect the current app — features, 55+ agents, configs/workbench/backup/cloud surfaces.

This release rebuilds the Local Backup panel around a live view of what the script is actually doing, and finally makes scheduled / “Run now” runs reflect in Recent changes instead of staying frozen until you click “Back up now”.

  • Live backup log + progress. The LOG section now auto-opens the moment a run kicks off, polls the log file every ~1 s, and auto-scrolls to the latest line — same mental model as tail -f. The progress label shows the freshest script line (e.g. Sync claude · skills (8/14)) instead of a static phase placeholder. The “Last backup …” result line gains a View log / Hide log toggle; when the LOG section is collapsed, the preview row shows the freshest log line instead of Last 80 lines available · 158.5 KB. The whole section moved up under Recent changes — script-level output and the manifest diff now sit next to each other.
  • Scheduled runs refresh the panel automatically. LAST_BACKUP.json moves out of the (possibly cloud-synced) backup folder and into a per-machine app-state directory (~/Library/Application Support/skillsafe-app/ on macOS, %LOCALAPPDATA%\skillsafe-app\ on Windows, ~/.local/state/skillsafe-app/ on Linux). Every generated bash / PowerShell backup script now drops a LAST_BACKUP.run sentinel at exit (started_at, finished_at, exit_code). On every panel refresh the app reads the sentinel and re-walks the destination when it’s newer than the manifest — so the 3 am scheduled run, manual “Run now”, and “Back up now” all keep the Recent changes list current. Previously only “Back up now” updated it.
  • Translations: Local Backup data-type labels. The data-type labels you see in the Local Backup picker and the BackupBrowser group pills (History & Memory, Skills, Tasks & plans, Settings & global instructions, Claude Desktop config, …) were rendered in English regardless of the active language. They now route through the same categories.* translation keys as the sidebar pills, and the keys are filled in across all six locales (en / es / fr / de / zh-CN / ja).
  • Guided fix for macOS CloudStorage permission denials. When rsync hits an “Operation not permitted” error on a folder under ~/Library/CloudStorage/..., the panel now surfaces the affected paths along with a “Show fix steps” expandable — both a quick fix (delete the listed folders so the running process recreates them with the access it needs) and a durable fix (System Settings → Privacy & Security → Full Disk Access).
  • Smaller fixes. Default scheduled backup time is now 22:00 daily. .DS_Store is filtered at every depth in the BackupBrowser file listing. Earlier in the cycle: unified Master & History views inside BackupBrowser, in-app preview for any backed-up file (markdown / text / image / “too large to inline” with an Open externally link).

This release lights up the desktop UI in six languages and reworks the Linux auto-updater so AppImage users get hands-off updates again.

  • Localization (6 languages). The desktop UI now ships translated for English, Spanish, French, German, Simplified Chinese, and Japanese. Coverage spans Settings, the sidebar, all core dialogs, list views, the Hooks / Keybindings / MCP / Permissions editors, Workbench / Master, the cloud catalog (RemoteList / Editor / Actions, share links, version actions), the update banner / dialog, history & diff panes, and the full Local Backup surface (BackupPanel + BackupBrowser). Locale is auto-detected from the OS on first launch and can be overridden from a new Language picker in Settings; the choice persists per machine.
  • Linux auto-updates via bundled AppImageUpdate. Linux AppImage installs no longer go through Tauri’s plugin-updater (its current_exe() relaunch path resolved into the still-mounted old SquashFS and looped silently). Instead, each AppImage now ships appimageupdatetool embedded inside it. On update check the tool reads the embedded zsync URL pattern, downloads only the changed chunks from the *.AppImage.zsync sidecar in the GitHub release, atomically rewrites the local AppImage in place, and relaunches from $APPIMAGE so the new SquashFS payload is mounted cleanly. Pre-v0.2.11 AppImage installs cross over via the existing Tauri-signed updater feed (a re-signed transitional bridge) — after that one hop, they’re on the new zsync path. Linux .deb / .rpm installs still surface a download-page sentinel (manual update only — apt / dpkg need root).
  • Skill installs drop the .agents/skills symlink bridge. Claude project-scope skill bundles are now written directly to <project>/.claude/skills/<name> like every other tool, instead of routing through <project>/.agents/skills/<name> plus a symlink. The bridge bought disk-sharing across tools but broke the moment a project synced to OneDrive / Dropbox / iCloud — cloud sync engines don’t preserve symlinks, so restores from backup decoupled. Existing bridged installs from prior versions remain readable, deletable, and listable; new installs just don’t create more of them.

A new Master tab consolidates Configs + Workbench into one cross-tool view of the artifacts you actually maintain across Claude Code, Codex, Cursor, and Cline — memory files, MCP servers, hooks, permissions, keybindings — and adds a master folder so one canonical body fans out to every tool you use.

  • Master folder. “Add to master” copies the live source into a diff-able, git-friendly folder (~/SkillSafe/master by default, or beside your backup destination). Drift badges show when a tool’s on-disk copy has diverged from the canonical, and Restore writes master back into the source.
  • Transfer + bind-as-source. Transferring a memory or MCP entry to another tool now auto-binds the destination as a source on the master entry. From then on, one canonical body keeps every bound tool in sync — Claude CLAUDE.md ↔ Codex AGENTS.md ↔ Cursor .cursor/rules/*.mdc ↔ Cline .clinerules. Per-source Restore + Unbind buttons live on each entry.
  • Cross-tool memory translation. Restoring to a tool that uses a different shape than the canonical (e.g. canonical authored in Claude markdown, restoring to Cursor) now runs through the same translator the Transfer dialog uses, so Cursor entries get MDC frontmatter and Claude/Codex stay plain markdown automatically.
  • Permissions / Hooks / MCP / Keybindings editors. Dedicated editors for each of these surfaces in their own row (was buried under Configs).
  • Toolbar cleanup across list views. Filter input + refresh icon at the top of every list (Artifact, Inventory, Remote, Local Backup); dropped the rarely-used ”+ New” and ”→” buttons. Local Backup auto-refreshes after master mutations.
  • Backups: per-tool subdirs. Each tool’s snapshot lives under <dest>/<tool>_backup/ with its own LAST_BACKUP.json, so concurrent runs for different tools never race on a shared manifest. Bash-flow backups also write the per-tool manifest now (was missing in 0.2.9).

Linux auto-updates work end-to-end again, plus a quiet fix for Windows that had been broken on the auto-update path since the move to Tauri v2.

  • Linux auto-updates restored. AppImage builds are back in the bundle (we’d dropped them in v0.2.7) and the bundler signs them for in-place updates. Run the AppImage once, and every future release lands automatically — no more “Update check failed: None of the fallback platforms” error.
  • Friendlier .deb update flow. Tauri’s bundler doesn’t auto-sign .deb, so .deb installs still can’t auto-update. Instead of throwing a cryptic error, the app now detects the install kind (via a small linux_installer_kind Rust command keyed on the APPIMAGE env var) and opens the download page when an update is available. Switch to the AppImage once and you’re on the auto-update path.
  • Windows auto-updates fixed. The release-manifest generator was looking for *-setup.nsis.zip.sig files, but Tauri v2’s self-contained updater signs *-setup.exe directly. Both latest.json and version.json now expose windows-x86_64 and windows-aarch64 entries that the updater can actually verify.
  • Changelog sort tiebreaker. Multiple releases on the same day now order newest-first by version (previously they fell back to filename order, putting the older patch on top of the day’s group).

Bug-fix release: Linux daily-backup install no longer fails with a cryptic OS error.

  • Linux backup scheduler routing fixed. detectPlatform() in the BackupPanel silently fell through to "macos" whenever osType() from @tauri-apps/plugin-os threw or returned an unrecognized value, sending the install handler into Command.create("launchctl", …) on Linux. Tauri’s shell plugin then surfaced Rust’s ENOENT verbatim as “Install failed: No such file or directory (os error 2)” — because launchctl isn’t a Linux binary. Detection now trusts osType() only when it answers windows/linux/macos, and cross-checks navigator.userAgent/platform before defaulting.
  • Scheduler-unavailable state no longer pretends to be installable. When the schedule status comes back unsupported (cron missing on Linux, schtasks missing on Windows, launchctl missing on macOS), the “Install daily backup” button is replaced with a “Scheduler unavailable” hint that names the missing tool per platform. Previously the button was clickable and produced the same ENOENT spawn error.
  • Linux-specific Install tooltip. The button now reads “Add a cron entry that runs the backup on the schedule below” on Linux instead of always describing a launchd job.

Linux ARM64 + Linux backup scheduling, in-app file editor, Windows ARM64.

  • Linux ARM64 support. *_arm64.deb for ARM64 Linux (Raspberry Pi 4/5, Ampere, Apple Silicon VMs running Ubuntu in QEMU/UTM/Parallels) joins the existing x64 build.
  • Linux scheduled backups via cron. The “Install daily backup” button now wires up a crontab(1) entry on Linux instead of falling through to the macOS launchd path. Foreign cron entries in your crontab are preserved untouched.
  • In-app file editor with edit history. Edit markdown frontmatter artifacts (skills, agents, commands, rules) directly inside SkillSafe. Every save is recorded; the new History panel shows previous versions and a Monaco-powered diff viewer for reviewing or rolling back.
  • Windows ARM64 installers. Native ARM64 Windows installer (Surface Pro X / Snapdragon X / Copilot+ PCs), cross-compiled from the windows-latest x64 runner.
  • Version in the window title. The app’s OS-level window title now reads AI SkillSafe v0.2.7, so you can see which build you’re on at a glance. The version badge that used to crowd the sidebar is gone.
  • Auto-updater “restart to update” actually restarts. The bottom-left affordance now calls installAndRelaunch so the new version applies on restart instead of relaunching the old one.
  • Slimmer release surface. Dropped AppImage and MSI bundles — every platform now has one canonical installer (.dmg / .deb / NSIS .exe). Linux installs from .deb are manual-update only since Tauri’s updater needs an AppImage to patch in place; macOS and Windows auto-updates are unchanged.

Cleaner installs and safer deletes for Claude project skills.

  • Install dialog now offers a “Use symlink” toggle (on by default). When on, a Claude project install writes the bundle to <projectRoot>/.agents/skills/<name> and creates a symlink at <projectRoot>/.claude/skills/<name> pointing to it. Claude Code auto-discovers skills under .claude/skills/ only, so the symlink is what makes the freshly-installed skill visible to it; the underlying .agents/skills/ location is the cross-tool universal layout used by npx skills add, so the same bundle can be reused by other agents on disk without duplication. Toggle the symlink off to install the bundle directly into .claude/skills/<name> as a real folder if you’d rather keep .agents/skills/ empty. Picking up the project hint, the dialog now shows the exact path that will be written under either choice, plus the secondary symlink path when the symlink is on.
  • Symlink target is now relative. A bug in the first cut of the bridge ran the relative path through Tauri’s path.join, which normalized the leading .. segments away and produced broken links resolving inside .claude/skills/ itself. The bridge now writes a literal ../../.agents/skills/<name> so the link survives moving the project root.
  • Listing dedupes the bridge symlink. Previously the same skill could appear twice in SkillSafe’s list (once via .agents/skills/, once via the .claude/skills/ symlink) — and clicking delete on the symlink row would recursive-rm through it and wipe the real bundle. The list now skips any entry under .claude/skills/ that is itself a symlink, so the canonical .agents/skills/<name> entry is the only one shown.
  • Delete is cascade-aware. deleteSkillBundle checks the artifact path before recursive-removal: if the path is a symlink, only the link is unlinked and the underlying bundle is left in place; if the path is the canonical bundle in .agents/skills/, the matching symlink in .claude/skills/ is also removed. The confirmation modal now spells out exactly which paths the delete will touch — single bundle, bundle + bridge symlink, or symlink-only — so the cascade is visible before the user confirms.
  • Diagnostic logs on the install path. When the symlink fails to create (e.g. Windows without Developer Mode), the failure now surfaces in DevTools as [install] failed to create bridge symlink … : instead of being silently swallowed.

Patch release: small UX fix in the Backup tools picker, plus the build-time fix that v0.2.4 was missing.

  • Backup → Tools & data types: clicking the tool name now expands or collapses the data-type tree instead of toggling the selection checkbox. Previously the entire row was a <label> for the checkbox, so clicking the tool’s name to peek at or hide its sub-options would silently flip the tool in or out of the backup. The name (and the n/m data types meta) is now its own button: it toggles the inline tree only, and the checkbox keeps its own click target for selection. Flat tools (those with only “all config files”) still toggle selection on name click since there’s no tree to expand.
  • Build fix that grounded v0.2.4. The v0.2.4 tag was pushed but every CI build job (mac/win/linux) failed at tsc -b on a BackupEntry.type narrowing in src/lib/backup/summary.ts (ArtifactType | undefined flowed in where Exclude<ArtifactType, "all"> | undefined was required). The local npm run typecheck script uses tsc --noEmit against a different tsconfig and didn’t catch it. Tightened SLOT_TO_TYPE and inferEntryFields to the same narrowed type. No v0.2.4 artifacts were ever published; clients should jump straight to v0.2.5.

Patch release: a single critical fix for the skillsafe:// deep-link crash that survived v0.2.2’s claimed repair.

  • Crash fix (real this time): skillsafe:// deep links no longer SIGABRT. The v0.2.2 changelog claimed the recursion crash was fixed by dropping tauri-plugin-single-instance’s deep-link feature and the duplicate JS listener. That addressed the JS-side path, but the Rust-side path was still wired and is what fresh v0.2.2 installs hit on every URL delivery.

    Root cause: tauri-plugin-deep-link emits deep-link://new-url itself on every URL delivery (RunEvent::Opened on macOS, single-launch CLI args on Linux/Windows, mobile event handler). on_open_url(f) registers f as a listener on that same event. The app’s Rust callback emitted the event again from inside its own listener, so Tauri’s flush_pending re-fired the listener, which emitted again — about 14000 recursion frames before the stack guard tripped and abort() killed the process.

    Fix: delete the on_open_url callback registration entirely. JS already subscribes via onOpenUrl() (a thin wrapper around listen('deep-link://new-url') from @tauri-apps/plugin-deep-link), so URLs reach the frontend through the plugin’s own emits without any Rust-side forwarding.

Local backup is now a single shell-script-driven path that honors the per-tool selector in Settings, with cleaner destination folders and a friendlier auto-update prompt.

  • Backup script honors the Tools picker. “Back up now” runs the same shell script that the daily launchd schedule does, with one rsync section emitted per selected agent. Changing the selection (or the destination, or the schedule) auto-regenerates the on-disk script so the next scheduled run picks it up — no manual reinstall needed.
  • Destination subdirs lose the _backup suffix. Per-tool mirrors now land at <dest>/claude/, <dest>/codex/, <dest>/cursor/, etc. — no more <tool>_backup/ clutter. Selecting claude still pulls Claude Desktop’s config files alongside, into a separate <dest>/claude_desktop/ subdir. The script no longer writes a LAST_BACKUP.txt summary to the destination — the rolling log + the app UI cover that.
  • Auto-update pill copy. The bottom-left “update ready” pill now reads “Restart to update to vX” instead of “Install vX”, more accurately describing what clicking it does.
  • Bug fixes. Resolved two duplicate-React-key warnings: backup-browser bucketing now includes the tool segment so same-named skill bundles across tools no longer collide, and the remote skill list deduplicates by skill_id defensively in case the account/search merge surfaces the same skill twice.
  • Crash fix: skillsafe:// deep links no longer abort the app. The combination of tauri-plugin-single-instance’s deep-link feature and a redundant frontend listener caused Tauri’s event dispatch to recurse on every URL delivery, hitting the stack guard and aborting via SIGABRT. Drop the single-instance feature flag (the deep-link plugin already handles macOS Apple Events natively) and the duplicate JS subscription; onOpenUrl alone covers every platform.
  • Bundle re-published 2026-05-05. Two follow-up fixes folded into v0.2.2: Settings → “Restart & install” no longer fails with Update.install called before Update.download (the dialog now uses downloadAndInstall since check() returns a fresh handle whose download state isn’t carried over), and the auto-update pill no longer washes out to pale --accent-soft on hover (the generic button:hover rule was overriding the accent background; restored explicitly).

The app now hides skills shipped by the underlying tool’s installer and only manages the skills you installed yourself.

  • Tool-shipped skills are hidden in listings. Vercel-style category prefixes (.system, .curated, .experimental) under ~/.<tool>/skills/ are reserved for bundles that ship with the CLI/agent installer. Those no longer appear in the artifact list — only skills you installed land directly under the skills root, so the UI shows just those.
  • Backups skip system bundles too. When you back up a tool’s skills, the mirror walks the source tree but ignores any top-level .system / .curated / .experimental directory. Your backup destination is no longer cluttered with category-prefixed bundles you didn’t install, and the file count + bytes shrink accordingly. Sub-directories inside a user bundle still mirror normally (so a versioned .git folder inside one of your own skills is unaffected).

One-click install from the web, fewer clicks to reach Settings, and a more resilient skill registry.

  • skillsafe:// deep-link install. Install links on the web (and in docs) now open AI SkillSafe directly with the install dialog pre-populated. The dialog includes a tool picker, so you can choose where the skill lands — Cursor, Claude Code, or any other registered tool — before confirming.
  • Deep-link from any panel into Settings. Feature panels can now jump straight to the relevant Settings section (tool integrations, cloud filters, etc.), so configuring the option you just discovered no longer requires hunting through the Settings tree.
  • Skill discovery is robust to broken symlinks. A broken or out-of-scope symlink inside a skill directory previously caused sibling skills in the same registry to be dropped. Now only the broken entry is skipped and everything else loads as expected.
  • Install dialog form polish. Radio buttons and checkboxes are no longer stretched to 100% width by the global input style.
0.1 series — initial launch 5 releases · May 1, 2026 – May 4, 2026

The auto-updater now fetches signed release manifests directly from GitHub.

  • Updater feed served from GitHub Releases. The Tauri updater’s primary endpoint is now releases/latest/download/latest.json, with app.skillsafe.ai/version.json kept as a fallback. New releases reach existing installs as soon as CI publishes the GitHub Release — no longer gated on a separate app-web deploy step.
  • Signed latest.json generated by CI. A new manifest job in the release workflow scans the build’s .sig files, picks the right one per platform (URL-encoding filenames that contain spaces), and uploads latest.json as a release asset. Re-runs are safe: the upload uses --clobber.
  • Older clients still served by app.skillsafe.ai. The version.json on this site continues to reflect the latest release, so v0.1.2 / v0.1.3 installs that haven’t yet pulled in the new updater config keep getting updates from here as a fallback.

Skill discovery now matches npx skills for every supported AI agent.

  • 50+ agents supported. Replaced the per-tool listers with a registry mirroring vercel-labs/skills. The Tool dropdown now includes Claude, Codex, Cursor, Cline, OpenClaw, Hermes, plus Aider-Desk, Amp, Antigravity, Augment, Continue, Crush, DeepAgents, Devin, Droid, Forge, Gemini CLI, GitHub Copilot, Goose, Junie, Kilo Code, Kiro CLI, Mistral Vibe, OpenCode, OpenHands, Qwen Code, Replit, Roo Code, Tabnine CLI, Trae, Warp, Windsurf, and many more — all reading skills from the locations npx skills add <agent> writes to.
  • Cloud install routes by tool. Installing a skill from skillsafe.ai now lands in the selected agent’s skills directory (e.g. ~/.cursor/skills, ~/.codex/skills) instead of always under ~/.claude/skills. The install dialog prompts for global vs project and shows the actual path.
  • Category-aware discovery. Dot-prefixed directories like .system, .curated, .experimental are treated as category folders (per the npx skills convention), not as 1-bundle catch-alls.
  • Backup robustness. The backup runner now handles registry-known agents whose source skills directory doesn’t exist on disk yet — no more “manifest cursor: failed to open file” errors when a tool was selected but had nothing to back up.
  • Rules listings retired. Cursor’s .cursor/rules and Cline’s .clinerules (a different concept from skills) are no longer surfaced; every tool’s “skill” type is a SKILL.md bundle.

Quieter auto-updater UX and friendlier first run.

  • Auto-updater: replaced the top “update available” banner with a floating bottom-left install button. Dismissing it persists by version, so once you skip a release it stays out of the way.
  • Auto-updater: download progress no longer flickers in the main window — it now lives in Settings → About alongside the existing “Restart and install” control.
  • Cloud: public skills install without a skillsafe.ai account; sign-in is only required to save, share, or install private skills. Removed the device-flow instruction blurb on the sign-in panel.

Maintenance release.

  • macOS: also ship a .pkg installer alongside the existing .dmg (the .dmg remains the default — unsigned .pkg files are blocked by Gatekeeper before our postinstall quarantine-strip can run).
  • macOS: auto-create ~/Library/LaunchAgents before installing the daily-backup schedule — fixes “No such file or directory (os error 2)” on fresh user accounts.

Initial public release.

  • Browse, edit, and convert markdown skills, agents, and commands across Claude Code, Codex CLI, Cursor, OpenClaw, and Cline.
  • Local backup runner with macOS launchd / cron scheduling.
  • skillsafe.ai cloud panel: install, save, share, and verify skills with cryptographic tamper detection.