2.9.0 - 2026-08-17
New Feature
Fall back through ssh, gh and https auth when cloning instead of giving up after ssh (#154)
Before This Release
Installing from a private GitHub repo, or updating skills that came from one, failed completely when ssh auth was unavailable or broken.
installfirst tried the https URL with credential helpers disabled, so it only ever succeeded for public repos. On failure it fell back to ssh once, and if ssh failed, the whole operation failed.updatecloned therepoUrlstored in the skill metadata. When that was an ssh URL - which it became after a previous fallback - there was no fallback at all, so one ssh failure was a total failure.search(thelist/read/installactions) shared the same clone logic asinstall.
Other auth methods the user may have working, such as gh or https credentials, were never tried.
After This Release
The clone logic now lives in a shared GitClone object used by install, update and search. For a github.com repo, in either URL form, it escalates through the available methods instead of giving up:
| Order | Method | What it does |
|---|---|---|
| 1 | anonymous |
https with credential helpers disabled (public repos) |
| 2 | ssh |
git@github.com:owner/repo.git (may prompt for a key passphrase) |
| 3 | gh |
gh used as a git credential helper |
| 4 | credential-helper |
https with the configured git credential helper |
| 5 | interactive |
asks first, then hands the terminal to git for its own prompt |
The failure is only reported after every method has been tried, and the report says what was attempted:
✖ Clone failed
anonymous: remote: Repository not found.
ssh: git@github.com: Permission denied (publickey).
gh: skipped (gh not found on PATH)
credential-helper: skipped (no git credential helper configured)
SSH, gh, and credential helper access all failed or are unavailable.
? Try https clone with username/password? (git will prompt, use a personal access token as the password) ›
‣ Yes — git will prompt for username/password
No — abort
The CLI never reads or stores credentials itself - git does its own prompting, and a personal access token works as the password.
Notes:
- The interactive last resort only runs when stdin is a TTY and
--yeswas not passed, so CI and piped runs degrade to the non-interactive steps and then fail with the report instead of hanging. - Non-GitHub https URLs also gain the credential-helper and interactive steps. Ssh-form and
git://URLs keep the previous single-attempt behavior. .aiskills.jsongains an optionalauthMethodfield recording the method that succeeded.updatemoves that method to the front of the chain rather than replacing the chain, then rewrites the metadata with whichever method actually won.repoUrlis now always stored in canonical https form forgithub.com, so it no longer flips between ssh and https across updates. Legacy records holding an ssh URL are repaired on the next successful update.- Metadata without
authMethodsimply runs the full chain, so no migration is needed.
Bug Fixed
Fixed: Skill's subpath should be normalized (#149)
Before This Release
The repo-root state had three representations (None, "" and "."), depending on which command wrote the metadata. aiskills install wrote "subpath": "" while aiskills search wrote "subpath": ".".
As a result, list / read showed
subpath: .
instead of <root>, and the overwrite / replace prompts showed my-skill (.) instead of my-skill (<root>).
After This Release
The invariant is enforced in SkillSourceMetadata itself, so "", "." and whitespace-only subpaths are all canonicalized to a single representation. The decoder is routed through the same path, so legacy .aiskills.json files already on disk are normalized on read as well, and a repo-root skill is written as "subpath" : null.
subpath: <root>
Fixed: Show <root> in the install selection list for repo-root skills (#151)
Before This Release
The install selection list interpolated the subpath verbatim, so a repo-root skill rendered as my-skill () while the other display helper already rendered <root> for the same skill.
After This Release
Both display helpers share one helper, so a repo-root skill renders consistently:
? Select skills to install ›
Tab to toggle, Shift+Tab to toggle all, Enter to submit.
◉ my-skill (<root>) 12.4KBSearch also builds its Git metadata through Install.buildGitMetadata instead of an inline record, so the Git metadata has a single construction site. This is the duplication that let the "."-subpath bug of #149 exist in only one of the two producers. The written .aiskills.json is unchanged.
Internal Housekeeping
Replace stringly-typed repo URLs with refined4s newtypes and Boolean flags with ADTs (#156)
A type-level refactor with no behavior change.
- Repo URLs and
owner/repoidentities used to travel as bareString. Tworefined4stypes now cover the URL domain across the whole codebase, so there is noString/ typed seam at any call site.RepoUrlis an unvalidated newtype covering every accepted clone source - https, ssh,git://and local.gitpaths.GitHubOwnerRepois a refined type whose predicate requires exactly two non-empty segments, so the GitHub URL builders can no longer be handed an arbitrary string.RepoUrlencodes as a plain string, so.aiskills.jsonis byte-identical to before.
- Four
Booleanflags that carried meaning their type could not express become five ADTs:GhCliStatus,CredentialHelperStatus,Interactivity,TerminalPromptandInteractiveCloneChoice. The capability gates, the skip notes in the failure report, the env selection and the prompt result handling are all exhaustive matches now, so adding a variant later produces a compiler warning rather than silently falling through.
New dependency:
refined4s:1.20.0(core, cats and circe modules, added toai-skills-core)
- Use
.someandOption.wheninstead of directSome/Noneconstructors inInstall,SearchandUpdate, following the 2020 Hindsight Scala practices for better type inference ofOption
What's Changed
- Reset version: to 2.8.1-SNAPSHOT by @kevin-lee in #148
- Close #149: Normalize SkillSourceMetadata.subpath so the repo-root subpath has a single representation by @kevin-lee in #150
- Close #151: Render
<root>in the install selection list for repo-root skills and reuseInstall.buildGitMetadatainSearchby @kevin-lee in #152 - Refactor by @kevin-lee in #153
- Close #154: Fall back through ssh,
gh, and https auth when cloning instead of giving up after ssh by @kevin-lee in #155 - Close #156: Replace stringly-typed repo URLs with refined4s newtypes and Boolean flags with ADTs by @kevin-lee in #158
- ai-skills v2.9.0 by @kevin-lee in #159
Full Changelog: v2.8.0...v2.9.0