Skip to content

Commit d9156af

Browse files
authored
feat: remove skills lockfile persistence (#33)
## Summary This PR makes `skills.json` the only user-facing configuration and pin source for skills-package-manager. It removes skills lockfile read/write/frozen behavior, resolves installs through an in-memory plan plus internal install state, updates add/update/patch/pnpm plugin flows, and expands `add` compatibility with common `npx skills add` forms while persisting GitHub sources as pinned `github:` specifiers. Tested with `pnpm build`, `pnpm build:website`, `pnpm test`, and scoped `biome check`. ## Related Links https://raw.githubusercontent.com/vercel-labs/skills/refs/heads/main/README.md ## Checklist - [x] Tests updated (or not required). - [x] Documentation updated (or not required).
1 parent 42d89de commit d9156af

69 files changed

Lines changed: 1316 additions & 3411 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

AGENTS.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
- `packages/skills-package-manager`: core library and `spm` CLI.
66
- `packages/pnpm-plugin-skills`: pnpm plugin that syncs skills during install.
77
- `website`: Rspress documentation site.
8-
- Root files such as `skills.json` and `skills-lock.yaml` document example skill manifests and lock state.
8+
- Root files such as `skills.json` document example skill manifests and pinned skill sources.
99

1010
## Documentation Structure
1111

@@ -19,7 +19,7 @@ Before you start your PR, check if you need to update the documents. The documen
1919
- **Architecture** (`architecture/`):
2020
- `how-it-works.mdx` - High-level system overview.
2121
- `cli-commands.mdx` - CLI command implementation details.
22-
- `manifest-and-lockfile.mdx` - Manifest and lockfile formats.
22+
- `manifest.mdx` - Manifest format and pinned specifier behavior.
2323
- `pnpm-plugin.mdx` - pnpm plugin integration details.
2424
- **Public Assets** (`public/`): Logos and favicon files.
2525

@@ -36,18 +36,18 @@ Before you start your PR, check if you need to update the documents. The documen
3636
- Use TypeScript and follow the existing module style in each package.
3737
- Match existing formatting, naming, and file organization before introducing new patterns.
3838
- Keep changes focused; avoid adding abstractions, comments, or files unless they are necessary.
39-
- Preserve manifest, lockfile, and CLI terminology consistently across code and docs.
39+
- Preserve manifest, specifier, and CLI terminology consistently across code and docs.
4040

4141
## Testing Expectations
4242

43-
- Add or update tests when changing CLI behavior, specifier parsing, install flow, or lockfile behavior.
43+
- Add or update tests when changing CLI behavior, specifier parsing, install flow, or install state behavior.
4444
- Prefer targeted tests under `packages/*/test`, following the existing `@rstest/core` style.
4545
- Run `pnpm test` before opening a pull request.
4646
- For docs-only changes, build the site with `pnpm build:website` if the change affects routing, components, or MDX structure.
4747

4848
## Commit and Pull Request Guidelines
4949

50-
- Use clear, conventional commit messages such as `feat: add file specifier validation` or `fix: preserve lockfile resolution`.
50+
- Use clear, conventional commit messages such as `feat: add file specifier validation` or `fix: preserve install state`.
5151
- Keep pull requests scoped to one change or theme.
5252
- Include a brief summary, testing notes, and screenshots for docs/UI changes when relevant.
53-
- Link related issues or context, and note any manifest or lockfile changes explicitly.
53+
- Link related issues or context, and note any manifest or install behavior changes explicitly.

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
<p>
1212
<strong>The Next-Gen Package Manager for <a href="https://skills-package-manager.site">Agent Skills</a></strong><br>
13-
Manage, install, and link SKILL.md-based skills with lockfile-driven reproducibility.
13+
Manage, install, and link SKILL.md-based skills from a single `skills.json` manifest.
1414
</p>
1515

1616
<p>
@@ -40,7 +40,7 @@
4040

4141
## ✨ Features
4242

43-
- 🔒 **Lockfile-Driven Versioning**Ditch heavy git commits. `skills-lock.yaml` ensures every team member runs on identical skill versions.
43+
- 📌 **Single-File Pins**Keep exact git commits and npm versions directly in `skills.json`.
4444
- 🌐 **Any Source, Any Skill** — Mix local `link:`, versioned `npm:`, or direct `git:` repos with ease—even sub-folders within `.tgz` archives.
4545
- 🚀 **npx skills compatible** — A seamless, drop-in replacement. Swap `npx skills` for `npx skills-package-manager` and unlock more power.
4646
- 🔌 **Native pnpm Integration** — The `pnpm-plugin-skills` hooks directly into your install lifecycle for zero-effort synchronization.
@@ -64,6 +64,10 @@ npx skills-package-manager add rstackjs/agent-skills
6464

6565
# 🎯 Direct — specify skill by name
6666
npx skills-package-manager add rstackjs/agent-skills --skill pr-creator
67+
npx skills-package-manager add rstackjs/agent-skills -s pr-creator -s rspress-custom-theme
68+
69+
# 🔎 List without installing
70+
npx skills-package-manager add rstackjs/agent-skills --list
6771

6872
# 📁 Local skill directory
6973
npx skills-package-manager add link:./my-skills/my-skill
@@ -75,14 +79,11 @@ npx skills-package-manager add link:./my-skills/my-skill
7579
npx skills-package-manager install
7680
```
7781

78-
> 💡 **Tip:** Use `--frozen-lockfile` in CI/CD to ensure reproducible installs without modifying the lockfile.
79-
8082
## 🏗️ How It Works
8183

82-
SPM uses two simple files to manage your agent's capabilities:
84+
SPM uses one manifest file to manage your agent's capabilities:
8385

84-
1. **`skills.json` (The Manifest)**: The single source of truth where you declare your requirements across any protocol.
85-
2. **`skills-lock.yaml` (The Lockfile)**: Deterministically locks every dependency to ensure every installation is identical.
86+
1. **`skills.json`**: The single source of truth where you declare pinned skill specifiers, `installDir`, and `linkTargets`.
8687

8788
## 📚 Documentation
8889

packages/pnpm-plugin-skills/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ A pnpm plugin that automatically installs agent skills during `pnpm install`.
77
This plugin hooks into pnpm's `preResolution` lifecycle to run skill installation before dependency resolution. On every `pnpm install`, it:
88

99
1. Reads `skills.json` from the workspace root
10-
2. Resolves and syncs `skills-lock.yaml`
10+
2. Resolves the manifest into an in-memory installation plan
1111
3. Materializes skills into the configured `installDir`
1212
4. Creates symlinks for configured `linkTargets`
13-
5. Skips if the lockfile hasn't changed (fast path)
13+
5. Updates the internal install state for future incremental runs
1414

1515
## Setup
1616

@@ -27,7 +27,7 @@ Then create a `skills.json` in your project root:
2727
"installDir": ".agents/skills",
2828
"linkTargets": [".claude/skills"],
2929
"skills": {
30-
"my-skill": "https://github.com/owner/repo.git#path:/skills/my-skill"
30+
"my-skill": "github:owner/repo#abc1234&path:/skills/my-skill"
3131
}
3232
}
3333
```

packages/pnpm-plugin-skills/src/index.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@ import { installCommand } from 'skills-package-manager'
33
export async function preResolution(
44
options: { lockfileDir?: string; workspaceRoot?: string } = {},
55
) {
6-
const lockfileDir = options.lockfileDir
7-
if (!lockfileDir) {
6+
const projectRoot = options.lockfileDir
7+
if (!projectRoot) {
88
return undefined
99
}
1010

11-
await installCommand({ cwd: lockfileDir })
11+
await installCommand({ cwd: projectRoot })
1212
return undefined
1313
}
1414

1515
export function afterAllResolved(
16-
lockfile: Record<string, unknown>,
16+
pnpmLockfile: Record<string, unknown>,
1717
_context: { log?: (message: string) => void } = {},
1818
) {
19-
return lockfile
19+
return pnpmLockfile
2020
}

packages/pnpm-plugin-skills/test/index.test.ts

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ async function loadPreResolution() {
2727
}
2828

2929
describe('preResolution', () => {
30-
it('installs skills from workspace root when manifest and lock exist', async () => {
30+
it('installs skills from workspace root when only skills.json exists', async () => {
3131
const root = mkdtempSync(path.join(tmpdir(), 'pnpm-plugin-skills-'))
3232
mkdirSync(path.join(root, 'skills-source/skills/hello-skill'), { recursive: true })
3333
writeFileSync(
@@ -48,23 +48,6 @@ describe('preResolution', () => {
4848
2,
4949
),
5050
)
51-
writeFileSync(
52-
path.join(root, 'skills-lock.yaml'),
53-
[
54-
"lockfileVersion: '0.1'",
55-
'installDir: .agents/skills',
56-
'linkTargets:',
57-
' - .claude/skills',
58-
'skills:',
59-
' hello-skill:',
60-
' specifier: link:./skills-source/skills/hello-skill',
61-
' resolution:',
62-
' type: link',
63-
` path: ${JSON.stringify(path.join(root, 'skills-source/skills/hello-skill'))}`,
64-
' digest: test-digest',
65-
].join('\n'),
66-
)
67-
6851
const preResolution = await loadPreResolution()
6952

7053
const result = await preResolution({
@@ -78,6 +61,8 @@ describe('preResolution', () => {
7861
'Hello from plugin',
7962
)
8063
expect(existsSync(path.join(root, '.claude/skills/hello-skill'))).toBe(true)
64+
expect(existsSync(path.join(root, 'skills-lock.yaml'))).toBe(false)
65+
expect(existsSync(path.join(root, '.agents/skills/lock.yaml'))).toBe(false)
8166
})
8267
})
8368

packages/skills-package-manager/README.md

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ For one-off usage, `npx skills-package-manager add ...` is the low-friction migr
99
```bash
1010
npx skills-package-manager --help
1111
npx skills-package-manager --version
12-
npx skills-package-manager add <specifier> [--skill <name>]
12+
npx skills-package-manager add <specifier> [--skill <name>...]
1313
npx skills-package-manager install
1414
npx skills-package-manager patch <skill>
1515
npx skills-package-manager patch-commit <edit-dir>
@@ -37,26 +37,37 @@ npx skills-package-manager add owner/repo
3737
# Interactive — clone repo, discover skills, select via multiselect prompt
3838
npx skills-package-manager add owner/repo
3939
npx skills-package-manager add https://github.com/owner/repo
40+
npx skills-package-manager add https://gitlab.com/org/repo
41+
npx skills-package-manager add git@github.com:owner/repo.git
42+
npx skills-package-manager add ./my-local-skills
4043

41-
# Non-interactive — add a specific skill by name
44+
# Non-interactive — add one or more specific skills by name
4245
npx skills-package-manager add owner/repo --skill find-skills
46+
npx skills-package-manager add owner/repo -s frontend-design -s skill-creator
4347
npx skills-package-manager add owner/repo@find-skills
4448
npx skills-package-manager add owner/repo#main@find-skills
4549

4650
# Direct repo subpath
4751
npx skills-package-manager add owner/repo/skills/my-skill
48-
npx skills-package-manager add https://github.com/owner/repo/tree/main/skills/my-skill#main
52+
npx skills-package-manager add https://github.com/owner/repo/tree/main/skills/my-skill
53+
54+
# Inspect or target agents with skills CLI-compatible flags
55+
npx skills-package-manager add owner/repo --list
56+
npx skills-package-manager add owner/repo --all
57+
npx skills-package-manager add owner/repo -a claude-code -a opencode
4958

5059
# Direct specifier — skip discovery
51-
npx skills-package-manager add https://github.com/owner/repo.git#path:/skills/my-skill
60+
npx skills-package-manager add github:owner/repo#abc1234&path:/skills/my-skill
5261
npx skills-package-manager add link:./local-source/skills/my-skill
53-
npx skills-package-manager add local:./.agents/skills/my-skill
62+
npx skills-package-manager add local:*
5463
npx skills-package-manager add ./local-source
55-
npx skills-package-manager add file:./skills-package.tgz#path:/skills/my-skill
56-
npx skills-package-manager add npm:@scope/skills-package#path:/skills/my-skill
64+
npx skills-package-manager add file:./skills-package.tgz&path:/skills/my-skill
65+
npx skills-package-manager add npm:@scope/skills-package@1.0.0&path:/skills/my-skill
5766
```
5867

5968
After `npx skills-package-manager add`, the newly added skills are resolved, installed or registered according to their protocol, and linked to each configured `linkTarget` immediately.
69+
GitHub sources are written back to `skills.json` as pinned `github:owner/repo#<commit>&path:<path>` specifiers.
70+
The `--copy` flag is accepted for `npx skills add` command-line compatibility; SPM still keeps one canonical install directory and links configured agent targets from there.
6071

6172
#### How it works
6273

@@ -65,7 +76,7 @@ When given `owner/repo` or a GitHub URL:
6576
1. Shallow-clones the repository into a temp directory
6677
2. Scans for `SKILL.md` files (checks root, then `skills/`, `.agents/skills/`, etc.)
6778
3. Presents an interactive multiselect prompt (powered by [@clack/prompts](https://github.com/bombshell-dev/clack))
68-
4. Writes selected skills to `skills.json` and resolves `skills-lock.yaml`
79+
4. Writes selected, pinned skill specifiers to `skills.json`
6980
5. Cleans up the temp directory
7081

7182
### `npx skills-package-manager init`
@@ -106,7 +117,7 @@ npx skills-package-manager install
106117
```
107118

108119
This resolves each skill from its specifier, installs managed skills into `installDir` (default `.agents/skills/`), registers `local:` skills in place, and creates symlinks for each `linkTarget`.
109-
When `selfSkill` is `true`, `npx skills-package-manager install` also installs the bundled `skills-package-manager-cli` skill so users get guidance for `skills.json`, `skills-lock.yaml`, and `npx skills-package-manager` commands. This helper skill is not written to `skills-lock.yaml`.
120+
When `selfSkill` is `true`, `npx skills-package-manager install` also installs the bundled `skills-package-manager-cli` skill so users get guidance for `skills.json` and `npx skills-package-manager` commands. This helper skill is injected at install time and is not written to `skills.json`.
110121
If `patchedSkills` contains an entry for a managed skill, the corresponding patch file is applied after the skill is materialized. `local:` skills cannot be patched because their source directories are user-owned.
111122

112123
### `npx skills-package-manager patch`
@@ -120,7 +131,7 @@ npx skills-package-manager patch hello-skill --edit-dir ./tmp/hello-skill
120131

121132
Behavior:
122133

123-
- Resolves the currently locked content for the target skill
134+
- Resolves the current manifest content for the target skill
124135
- Extracts an editable copy into a temporary directory by default
125136
- Reapplies any committed patch for that skill unless `--ignore-existing` is passed
126137
- Writes patch edit metadata so `patch-commit` can generate a new patch file later
@@ -139,12 +150,11 @@ Behavior:
139150
- Compares the edited directory with the original resolved skill content
140151
- Writes a unified diff patch file to `patches/<skill>.patch` by default
141152
- Updates `skills.json` through the `patchedSkills` field
142-
- Updates `skills-lock.yaml` with patch path and digest metadata
143153
- Reinstalls and relinks the patched skill so the working tree reflects the committed patch
144154

145155
### `npx skills-package-manager update`
146156

147-
Refresh resolvable skills declared in `skills.json` without changing the manifest:
157+
Refresh resolvable skills declared in `skills.json` and write the updated pins back to the manifest:
148158

149159
```bash
150160
npx skills-package-manager update
@@ -154,10 +164,10 @@ npx skills-package-manager update find-skills rspress-custom-theme
154164
Behavior:
155165

156166
- Uses `skills.json` as the source of truth
157-
- Re-resolves git refs and npm package targets
158-
- Skips local `link:` and `local:` skills, including the bundled self skill
167+
- Updates git skills to the latest `main` commit and npm skills to the registry `latest` version
168+
- Skips local `link:`, `local:`, and `file:` skills
159169
- Fails immediately for unknown skill names
160-
- Writes `skills-lock.yaml` only after fetch and link succeed
170+
- Writes `skills.json` only after the updated install succeeds
161171

162172
## Programmatic API
163173

@@ -182,14 +192,15 @@ const skills = await listRepoSkills('vercel-labs', 'skills')
182192
## Specifier Format
183193

184194
```text
185-
git/file/npm: <source>#[ref&]path:<skill-path>
195+
git/file/npm: <source>[#ref][&path:<skill-path>]
186196
link: link:<path-to-skill-dir>
187197
local: local:<path-to-existing-skill-dir>
198+
local shorthand: local:*
188199
```
189200

190201
| Part | Description | Example |
191202
|------|-------------|---------|
192-
| `source` | Git URL, direct `link:` or `local:` skill path, `file:` tarball, or `npm:` package name | `https://github.com/o/r.git`, `link:./local/skills/my-skill`, `local:./.agents/skills/my-skill`, `file:./skills.tgz`, `npm:@scope/pkg` |
203+
| `source` | Git URL or `github:` shorthand, direct `link:` or `local:` skill path, `file:` tarball, or `npm:` package name | `github:o/r`, `https://github.com/o/r.git`, `link:./local/skills/my-skill`, `local:*`, `file:./skills.tgz`, `npm:@scope/pkg@1.0.0` |
193204
| `ref` | Optional git ref | `main`, `v1.0.0`, `HEAD`, `6cb0992`, `6cb0992a176f2ca142e19f64dca8ac12025b035e` |
194205
| `path` | Path to skill directory within source | `/skills/my-skill` |
195206

@@ -201,7 +212,7 @@ local: local:<path-to-existing-skill-dir>
201212
- **`link`** — Symlinks a local skill directory into `installDir`
202213
- **`local`** — Uses an existing user-owned skill directory in place
203214
- **`file`** — Extracts a local `tgz` package and copies the selected skill
204-
- **`npm`** — Resolves a package from the configured npm registry, locks the tarball URL/version/integrity, and installs from the downloaded tarball
215+
- **`npm`** — Resolves a package from the configured npm registry and installs from the downloaded tarball
205216

206217
`npm:` reads `registry` and scoped `@scope:registry` values from `.npmrc`. Matching `:_authToken`, `:_auth`, or `username` + `:_password` entries are also used for private registry requests.
207218

@@ -212,7 +223,7 @@ src/
212223
├── bin/ # CLI entry points
213224
├── cli/ # CLI runner and interactive prompts
214225
├── commands/ # add, install, patch command implementations
215-
├── config/ # skills.json / skills-lock.yaml read/write
226+
├── config/ # skills.json read/write and in-memory install plan resolution
216227
├── github/ # Git clone + skill discovery (listSkills)
217228
├── install/ # Skill materialization, linking, pruning
218229
├── patches/ # Patch edit state, diff generation, patch application
@@ -231,4 +242,3 @@ pnpm build # Builds with Rslib (ESM output + DTS)
231242
```bash
232243
pnpm test # Runs tests with Rstest
233244
```
234-
``

0 commit comments

Comments
 (0)