Changelog

Each release below lists the changes you can see or act on. Releases that need action from you end with migration notes. If you skip a release when you upgrade, read its migration notes too.

0.9.0 - 2026-09-27

Highlights

  • Catalogs choose where usage metrics go. A catalog that names an address in metrics_url in its catalog.yaml receives anonymous usage counts from everyone who has it. Usage metrics are on until you turn them off, and SkillCatalog has no address of its own.
  • Delivery skips only what it cannot deliver. When a profile or skill cannot be delivered, SkillCatalog still delivers the rest, lists what it skipped, and exits 25 with delivery-failed.
  • A desktop save publishes only what you saved. On a direct catalog, a save commits and pushes the files of the item you saved. Other changes in the clone wait for Sync.
  • Review-branch syncs keep your work. Sync sends commits left on the primary branch as a proposal, merges a later edit into a waiting proposal, and puts your edits back when the Git host refuses a push.
  • Skills for a second folder. skc install --target-dir <folder> delivers a checkout's skills into another folder.
  • Matching files are taken over only when you ask. Delivery no longer takes over a file it did not write, even one that matches. skc deliver --adopt-matching does it on request.

Several exit codes changed. If your scripts check them, read the migration notes at the end of this release before you upgrade.

Added

  • skc install --target-dir <folder> delivers a checkout's skills into another existing folder, and later skc install, skc deliver, and skc update runs keep delivering there. skc profile show prints a Delivers to: line for such a profile, and the desktop Delete profile dialog names the folder. The JSON output of skc profile list, show, create, add, remove, and reorder adds delivery_directory. See Use the skills in a second checkout.
  • A catalog can collect anonymous usage counts. When its catalog.yaml names an address in metrics_url, everyone who has the catalog sends counts there while usage metrics are on. SkillCatalog asks nothing first. The address receives counts about its own catalog and that catalog's skills, stacks, and bundles, named by catalog id and slug, and how often each skc and desktop command ran, with its outcome and duration. It never receives counts about another catalog. See Usage metrics.
  • skc catalog add <url> --metrics-url <address>, or the Metrics address field of the desktop Add Catalog dialog, writes the address into the catalog.yaml that the add creates for an empty repository. For a repository that already has a catalog, the add succeeds without it and warns how to set it by hand. When you add a catalog that names an address while usage metrics are on, skc catalog add, skc install, skc update, and the desktop app show the address. JSON output adds metrics_url either way. skc validate --path warns when metrics_url is not a valid address. SkillCatalog ignores such a value, so no counts are sent for that catalog.
  • skc settings telemetry and the desktop Settings page list the catalogs that have a metrics address. skc settings telemetry --disable, or turning off Send usage metrics in Settings, stops sending from both the desktop app and skc, and --enable turns it back on. SkillCatalog ignores every OTEL_EXPORTER_OTLP_ environment variable.
  • A validation: map in catalog.yaml turns each of the four advisory content checks on or off for the whole catalog. The skillcatalog/validation metadata key in a skill's SKILL.md overrides the catalog's choice for that skill. See Check a skill before you share it.
  • In a SKILL.md, \@skill-dir and \@skill:<slug> stay plain text: delivery removes the backslash and replaces nothing, and skc validate does not check them. See Refer to other skills.
  • skc validate reports leftover Git conflict markers in a SKILL.md, outside fenced code blocks, as validation.conflict-markers, and a symbolic link in a skill folder as catalog-integrity-error. Both are errors, so they also stop commits to the catalog. See A commit stops on leftover conflict markers.
  • skc validate, skc status, and skc deliver --dry-run report two entries in one profile that deliver the same skill. The skc validate finding is profile-slug-conflict.
  • skc sync warns about each catalog that has recovery files from syncs that did not finish. skc profile add and skc install warn when nothing was delivered because no AI tool is turned on. Both warnings go to standard error. See Recover unpublished changes.
  • skc catalog list --json adds last_synced_at, the time skc sync last synced each catalog.

Changed

  • Interactive skc sync shows each catalog's changed files and asks for that catalog's own commit message. If the files change before it commits, it shows them again. Without a terminal and without --message, sync refuses and lists each changed catalog and its files, in error.details.dirty_catalogs in JSON output.
  • When some profiles or skills cannot be delivered, delivery delivers the others, lists the rest, and exits 25 with delivery-failed. This covers an entry whose item is gone, a missing checkout or --target-dir folder, a symbolic link in a skill folder, and a catalog whose proposal state is unknown. A skipped skill keeps the copies delivered earlier. skc deliver exits 43, 44, or 45 only when no profile with entries can be delivered. This applies to skc deliver, skc sync, skc install, skc update, and the desktop app. 0.8.1 delivered nothing in these cases.
  • skc sync also exits 25 when its delivery reports conflicts or failed items, and skc deliver --dry-run exits 25 when the delivery would skip a profile or skill, or two entries would deliver the same skill. Both exited 0 in 0.8.1.
  • Delivery no longer takes over a file it did not write when the file is exactly what it would write. It reports the file as unmanaged_target_exists and names skc deliver --adopt-matching, which takes over such files and never overwrites a file with different content. skc deliver <profile-id> --adopt-matching works on one profile. The desktop Replace and deliver card says it takes these files over, and it also appears when other items failed. See A skill folder already exists.
  • Delivery refuses a tool's skills folder that is a symbolic link, such as ~/.claude/skills linked to ~/.agents/skills, also with --adopt-matching. Each file of that tool is reported as unsafe_parent_path. 0.8.1 took over matching files through the link.
  • Delivery skips .DS_Store, files ending in .pyc, .pyo, .pyd, .swp, or ~, anything under __pycache__, .git, or node_modules, and files that Git ignores in the catalog. It stops with an error when a selected skill's SKILL.md is Git-ignored. See Skill folders.
  • A desktop save on a direct catalog commits and pushes only the files of the item you saved, and says how many other changed files wait for Sync. The save stops when an unsynced change touches the item's own files, or when the item uses a skill, stack, category, owner, or tag that is not synced yet. 0.8.1 committed every change in the clone. See What a desktop save does.
  • On a review-branch catalog, skc sync sends the commits on the primary branch that the Git host lacks as one proposal, then moves the primary branch back to the host's version. When those commits are all it sends, it reports push pushed. When they conflict with the host, sync stops and prints a git reset --soft command that turns them into a proposal. 0.8.1 neither pushed nor reported them.
  • After you remove a catalog in the desktop app, the profile entries that use it stay, marked Unavailable. Until you remove them, their profiles are not delivered and skc deliver and skc sync fail. Other profiles are still delivered. 0.8.1 deleted those entries the next time the app started.
  • skc update and a repeated skc install add any catalog that the team manifest names and this machine lacks, as a first install does, and skc update --check reports it with missing-registered-catalog-id. Both commands print Registered catalog '<id>' ... for each catalog they add, also on a first install and when the run fails later. The JSON output of a successful skc install always has data.registered_catalogs. See Update a checkout.
  • skc profile add refuses an item that its catalog does not have, with skill-not-found, stack-not-found, or bundle-not-found, and says when the slug exists as another kind. 0.8.1 saved the entry, which then stopped the delivery of every profile.
  • skc skill list lists the skills it can read, exits 0, and warns on standard error about each skill it cannot read, which its JSON output lists in invalid_items. The desktop Skills page shows an error row for each. 0.8.1 failed when one skill could not be read.
  • The date and version check, validation.time-sensitive.outside-old-patterns, reports info findings, which never fail skc validate or make skc status report inconsistent state. It ignores bare numbers such as 2048 and text inside code.
  • The check before each commit to a catalog no longer checks delivered copies, so an edited delivered file does not stop commits. Catalogs added from the desktop app run the check too, from their next sync or save. When the check fails, its advice matches the failure.
  • A missing stacks/ or bundles/ folder counts as empty everywhere, including in skc validate --path. A catalog still needs skills/.
  • skc skill improve previews a diff of SKILL.md, with three unchanged lines around each change, in place of the whole old and new file.
  • skc skill score-history <slug> --repair keeps the original SCORE.json in ~/.skillcatalog/score-history-backups/<catalog-id>/<slug>/. 0.8.1 wrote it into the skill's folder, where delivery and sync picked it up. The error for an oversized SCORE.json names --repair.
  • Log files show skill and catalog names as short codes, such as rev~a1deb48cb5, that differ between installations. Catalog ids, file paths, and Git's error output still appear in full, so read a log before you share it. See Find and share logs.
  • The Essentials catalog's skills describe 0.9.0. They tell AI agents to sync, publish, remove a catalog, apply an improvement, or delete content only when you ask. SkillCatalog updates your copy of the catalog automatically.
  • Several commands report different exit codes and outcomes, such as skc update --check, skc deliver --check, and skc profile add. The table in the migration notes lists every case. skc install no longer reports catalog-removed (exit 22), and no command reports profile-catalog-binding-missing, profile-child-catalog-binding-forbidden, or profile-catalog-conflict, which nothing raised.
  • skc profile reorder <profile-id> --entry takes kind:catalog-id:slug, the same form as skc init and skc profile create. The catalog-id:kind:slug form of 0.8.1 still works.

Fixed

  • The desktop editors say whether a save was published or saved as a proposal waiting for review. When delivery fails after a save, the message says the change was saved and gives the hint "Run Sync to retry delivery." When the push fails after the commit, the message says the change is saved on this computer and that Sync publishes it. 0.8.1 said every save stayed local until you synced, and that a failed push would be retried, which nothing did.
  • On review-branch catalogs, the desktop editors open a skill, stack, or bundle that exists only in a pending proposal, and saving updates that proposal. The stack and bundle editors offer only merged skills and stacks as new members, plus the ones the draft already contains. A save from a clone on another branch names both branches and tells you to switch back, and the Catalogs page shows the primary and review branches, which 0.8.1 showed as undefined.
  • In the desktop editors, switching catalogs with unsaved changes asks before discarding them, and clearing a skill's category or an item's owner saves the change. The History tab of a stack or bundle lists the changes to its .yaml file. The drift confirmation says that Deliver recreates deleted files and keeps edited ones, where 0.8.1 said your edits would be lost.
  • While a proposal waits, skc sync merges a later edit of the same file into the proposal's version. When both change the same lines, sync stops and puts your edit back in the clone. 0.8.1 replaced the proposal's copy of the file, so the proposal lost its earlier changes. See What a save does.
  • When the Git host refuses a proposal's push, skc sync puts your edits back in the clone, uncommitted, so a later sync publishes them. 0.8.1 left them on a local branch that no later sync pushed. On review-branch catalogs, sync also stops while the clone has an unfinished merge, rebase, or cherry-pick.
  • A push that the Git host refuses shows the host's reason, in the text of skc sync, in push.message of its JSON output, and in the desktop Sync Center under Show exact catalog and delivery records. 0.8.1 showed up_to_date or a generic error.
  • A review-branch sync that sends your edits as a proposal reports push proposal and the branch, and the desktop Sync Center says each change went out as a proposal on its own branch. skc proposal list and skc proposal show print each proposal's status, such as pending review, closed, or status unknown, and skc proposal show finds a proposal after its catalog switched back to direct. 0.8.1 printed push nothing to push, and (pending review) for every proposal.
  • On review-branch catalogs, applying an improvement (skc skill improve --apply or --apply-proposal, or the desktop app) pushes it as a proposal, and delivery uses the catalog's current SKILL.md until the proposal is merged. 0.8.1 wrote the improvement into your clone before review. Applying an improvement also rejects an improved SKILL.md whose metadata SkillCatalog cannot read, before writing anything.
  • When a sync cannot commit, for example because a pre-commit hook rejects the commit, it restores exactly what was staged in your clone. 0.8.1 left partly staged files fully staged.
  • skc catalog remove <catalog-id> --force removes a registration that SkillCatalog cannot read, such as one without a source URL, and keeps the catalog's local files and the profile entries that use it. In 0.8.1 this command failed with the same error that told you to run it. skc catalog remove also counts the entries in a checkout's local manifest, and its hint lists one skc profile remove command for each entry.
  • Deleting a skill, stack, or bundle in the desktop app removes only that item's entries from your Home and personal profiles, after a delete on a direct catalog or after you discard a proposal that created the item. 0.8.1 also removed unrelated entries, such as Unavailable and misspelled ones. An entry that stays, for example after a delete on a review-branch catalog, stops its profile's delivery once the item is gone, so remove it yourself.
  • When delivery removes a skill, it also removes the skill's empty folder from each tool's skills folder.
  • After skc uninstall kept a file you edited, a later skc install in the same checkout keeps the edit and lists it as preserved. 0.8.1 failed with unmanaged_target_exists.
  • Error messages name what went wrong. A pull conflict names each file that Git could not merge, another-sync-running names the busy catalog, and skc catalog add explains a repository that has commits but no catalog.yaml. skc proposal verify-clean names each problem, and fails when the clone is not on the primary branch, has a detached HEAD, or has a primary branch ahead of or behind origin. Messages no longer show internal names, and skc update --help, skc sync --help, and skc deliver --help show the full help.
  • Sharing a skill in the desktop app ignores its SCORE.json, so an unsynced score no longer stops the link.
  • The desktop log preview and log package replace paths under /private/tmp, /private/var/folders, and /Volumes with markers, and in most cases hide the rest of a path after a space in a folder name. 0.8.1 showed those paths in full.

Security

  • HTTPS connections from the desktop app and skc, such as the desktop update check and usage metrics, use rustls 0.23.45, which fixes RUSTSEC-2026-0285.
  • skc sync and desktop saves refuse a catalog clone whose own Git data is damaged, and change nothing. When such a clone was inside another repository, such as a dotfiles repository in your home folder, 0.8.1 committed the change there and pushed it to that repository's remote.
  • When SkillCatalog syncs, saves, or publishes, its Git commands ignore GIT_DIR, GIT_WORK_TREE, and other environment variables that point Git at another repository, so a shell or hook that sets them cannot redirect sync, saves, or proposals.

Migration from 0.8

  • Usage metrics. A catalog whose catalog.yaml names a metrics address receives anonymous usage counts from everyone who has the catalog, without asking. skc settings telemetry and the desktop Settings page list these catalogs. To stop sending, run skc settings telemetry --disable, or turn off Send usage metrics in Settings.
  • Validation results. Date and version findings are info instead of warnings, so skc validate and skc status pass when these are the only findings. Scripts that read severity from skc validate --json must accept info. With --quiet, a report that has only info findings prints nothing.
  • Delivered files. The first delivery after you upgrade removes the files that 0.9.0 skips from your tools' skills folders, unless you edited them. If a skill needs a file that Git ignores in the catalog, stop ignoring it.
  • Sync prompts. Interactive skc sync asks for one commit message per changed catalog. To use one message for all of them, pass --message.
  • Removed catalogs. After you remove a catalog in the desktop app, remove the profile entries marked Unavailable, or add the catalog again. Until you do, the profiles with those entries are not delivered, and skc deliver and skc sync fail.
  • Files that match but were not delivered. Delivery does not take over a file it did not write, even one that matches the catalog's version. After a lost delivery record, or with a skill folder copied by hand, delivery reports those files as unmanaged_target_exists. Run skc deliver --adopt-matching to take them over.
  • Linked skills folders. When a tool's skills folder is a symbolic link, as when ~/.claude/skills points to ~/.agents/skills, delivery fails for that tool, also with --adopt-matching. Remove the link, then run skc deliver, which delivers a separate copy into each tool's folder.
  • Old repair backups. In 0.8.1, skc skill score-history <slug> --repair left a SCORE.json.repair-backup-<number>.json file in the skill's folder. Delivery cannot read such a large file and stops for every profile. Move each one out of the catalog, then sync. See SCORE.json is too large to read.
  • Checks before each commit. A SKILL.md with leftover conflict markers, or a skill folder with a symbolic link, fails skc validate and stops every commit to its catalog. In a catalog added from the desktop app, the check starts at its next sync or save. After you upgrade, run skc validate and fix what it reports before you sync.
  • Going back to 0.8.1. SkillCatalog 0.8.1 cannot read a project profile installed with --target-dir, and then fails to deliver any profile on that machine. Before you downgrade, run skc uninstall with 0.9.0 in that checkout.
  • Teammates on 0.8.1. SkillCatalog 0.8.1 cannot read a skill whose SKILL.md sets skillcatalog/validation, so its deliveries that include the skill fail. It ignores validation: and metrics_url: in catalog.yaml, and its desktop app drops both keys when it saves a category, owner, or tag change. Upgrade everyone who uses a catalog before you add these keys to it.
  • Scripts. Scripts that check exit codes or outcomes must handle the changes below. See Exit codes.
Command and case0.8.10.9.0
skc deliver: some profiles or skills cannot be delivered43 or 45, nothing delivered25 delivery-failed, the rest delivered
skc sync: its delivery reports conflicts or failed items025 delivery-failed
skc deliver --dry-run: the delivery would skip a profile or skill, or two entries would deliver the same skill025 delivery-failed
skc deliver, skc install, skc update: a file matches the catalog's version, but SkillCatalog did not write it0, file taken over25 delivery-failed
skc update --check: delivery would skip skills025 delivery-failed
skc update --check: a file matches the catalog's version, but SkillCatalog did not write it024 delivery-blocked
skc update, or a repeated skc install: the team manifest names a catalog this machine has not added17 or 220, catalog added
skc deliver --check: a checkout is missing1926 delivery-check-drift
skc deliver: a Home profile stores a team manifest path19 manifest-missing24 home-profile-parent-metadata
skc profile add: the catalog lacks the item010 skill-not-found, stack-not-found, or bundle-not-found
skc profile add, remove, or reorder: an argument mistake on a project profile24 manifest-malformed10 user-input-invalid
skc profile delete: the profile does not exist24 profile-write-failed10 profile-not-found
skc init: no terminal, and required flags are missingwaits for input10 user-input-invalid
skc skill list: a skill cannot be read23 catalog-read-failed0, the skill listed in invalid_items
skc sync: a busy lock stops a review-branch commit4434 another-sync-running
skc help-json: the reader stops early70 internal-error0

0.8.1 - 2026-07-26

Changed

  • A repeated skc install pulls the catalogs that the checkout's team and local manifests declare before it delivers. A first install does the same when it did not need to clone any of them. If a pull fails, install stops with catalog-refresh-failed before it saves the profile or delivers. A pull also fails when a review-branch catalog's clone is not on its primary branch.
  • skc install, skc update, and skc deliver report manifest-changed when the team manifest changes while they run and they have written nothing, so you can run them again. When one of them, or skc profile add, remove, or reorder, has already written something, it reports an outcome that starts with changed-after-. The rest of the name says what it wrote. See Exit codes.
  • The Essentials catalog's skills are corrected where they did not match SkillCatalog, and SkillCatalog updates your copy of the catalog automatically.

Fixed

  • skc validate ignores SkillCatalog's own ~/.skillcatalog/profiles/.committed-profile-locks folder. 0.8.0 reported it as a broken profile.

0.8.0 - 2026-07-14

Added

  • A local manifest, .skillcatalog/skillcatalog.local.yml, holds your own changes to a checkout's project profile: extra entries, and under excludes:, team entries you do not want. See Make personal changes.
  • skc profile add, skc profile remove, and skc profile reorder on an installed project profile write to the local manifest and never change the team manifest. Removing a team entry adds it to excludes:.
  • SkillCatalog adds .skillcatalog/skillcatalog.local.yml and .skillcatalog/.skc-recovery/ to the checkout's .gitignore when it writes the local manifest.
  • skc profile show <profile-id> --effective lists the local manifest entries, the team manifest entries marked as shadowed or excluded, and the entries that SkillCatalog delivers.
  • skc validate warns with local-exclude-no-match about an exclusion that matches no team entry.
  • In the desktop app, a project profile shows the team manifest's entries as Inherited, and you can exclude them.

Changed

  • skc init writes the team manifest to .skillcatalog/skillcatalog.yml. A root-level skillcatalog.yml keeps working while the new file does not exist. If both exist, commands stop with an error.
  • skc profile show <profile-id> --effective replaces its Inherited parent entries list with Local manifest entries and Team manifest entries. In its JSON output, team entries have origin: "team" instead of "inherited".
  • The JSON output of skc profile show <profile-id> --effective adds local_profile, team_profile, and excluded_by_local, and keeps inherited_profile as an alias of team_profile.

Migration from 0.7

  • Scripts. Scripts that read origin from skc profile show <profile-id> --effective --json must accept "team".
  • Personal entries. Entries you added to an installed project profile move into .skillcatalog/skillcatalog.local.yml the next time SkillCatalog installs, updates, delivers, or changes that profile.
  • Team manifest location. A root-level skillcatalog.yml keeps working. To move it, move the file to .skillcatalog/skillcatalog.yml and commit the move. Installed profiles follow it.

Earlier releases

Releases before 0.8.0 are on the SkillCatalog releases page.