Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Purview.BuildSdk 1.3.1 - managed file, do not edit
# Purview.BuildSdk 1.3.2 - managed file, do not edit
#
# This file is written by Purview.BuildSdk and is replaced whenever the SDK version changes. The version
# on the first line is how the SDK recognises a file it owns: a .editorconfig without that marker is
Expand Down
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ The authored set, and what each one answers:
| [`purview-buildsdk-skill-tests`](./skills/purview-buildsdk-skill-tests/SKILL.md) | authoring a skill, and validating it with `Purview.Skills.Testing` |
| [`purview-buildsdk-skill-installation`](./skills/purview-buildsdk-skill-installation/SKILL.md) | installing the skills a package ships, and the `PRSKL*` diagnostics |
| [`purview-buildsdk-repository-review`](./skills/purview-buildsdk-repository-review/SKILL.md) | auditing a repository against the SDK's conventions |
| [`purview-buildsdk-justfile`](./skills/purview-buildsdk-justfile/SKILL.md) | adding or updating `just` recipes that run the skill targets |
| [`purview-buildsdk-skills-justfile`](./skills/purview-buildsdk-skills-justfile/SKILL.md) | adding or updating `just` recipes that run the skill targets |

After editing one, run `just skills-validate` for the pack-time check and `just test` for the full rule set.

Expand Down Expand Up @@ -208,7 +208,7 @@ cost was pure duplication. The remaining work is now paid only when somebody ask
dotnet msbuild <project> -t:RecommendPurviewSkills # report, never fail
dotnet msbuild <project> -t:VerifyPurviewSkills # report, and fail on anything unverifiable
dotnet msbuild <project> -t:InstallPurviewSkills # install every shipped skill at its package's commit
dotnet msbuild <project> -t:UpdatePurviewSkills # re-add every skills-lock.json source, then 'skills update'
dotnet msbuild <project> -t:UpdatePurviewSkills # re-add every skills-lock.json source: refresh, and add new skills
dotnet msbuild <project> -t:CheckPurviewSkills # only the PurviewSkillsAgents directories exist
dotnet msbuild <project> -t:FixPurviewSkills # remove the CLI's links from any other agent directory
dotnet msbuild <project> -t:ListPurviewSkills # what the restored packages ship
Expand Down Expand Up @@ -248,7 +248,7 @@ own `.slnx` because the harness's lists projects as `<File>` entries.

**Install, update and fix run only when named — never automatically.** Two layers, both tested in `PurviewSkillTargetIsolationTests`: no SDK target hooks or depends on them (a structural scan of every `.props`/`.targets` under `Sdk/`, including `*DependsOn` properties), and `_GuardExplicitPurviewSkillsTarget` — first in each one's `DependsOnTargets` — fails with `PRSKL0009` when `BuildingProject`, `DesignTimeBuild` or `MSBuildIsRestoring` is true, which catches a consumer's own `AfterTargets="Build"` hook. Do not add a `BeforeTargets`/`AfterTargets` to any of them, and do not weaken the guard.

`UpdatePurviewSkills` (`ReadPurviewSkillsLockSources` inline task) re-adds each unique lockfile source once, naming only the skills the lockfile records for it. A source a restored package ships is re-added at **that package's commit**, never unpinned — re-adding it at latest would turn a satisfied entry into `PRSKL0011` drift. Every other source is re-added at latest. Then `skills update -y -p` runs per `PurviewSkillsUpdateMode` (`Auto`: only when the lockfile hash changed; `Always`; `Never`). `skills update` re-fetches each entry at its recorded ref — verified in the CLI source — so it cannot undo the pin. The re-adds use target batching (`_UpdatePurviewSkillsSource`) so each failure is attributed to its source (`PRSKL0008`, `ErrorAndContinue` so all are named); `-p:PurviewSkillsDryRun=true` prints and runs nothing.
`UpdatePurviewSkills` (`ReadPurviewSkillsLockSources` inline task) re-adds each unique lockfile source once, and **that is the whole update — `skills update` is never run**. `skills add` reinstalls every skill it selects (verified in the CLI source, skills 1.7.6: `installSkillForAgent` cleans each skill's folder and copies it again, skipping only when source and destination are the same folder), so one re-add both refreshes the installed skills and adds any the source has gained; `skills update` only re-fetches entries the lockfile already has, so it would add nothing. A source a restored package ships is re-added at **that package's commit**, never unpinned — re-adding it at latest would turn a satisfied entry into `PRSKL0011` drift — naming every skill that package version ships. Every other source is re-added at latest with `--skill "*"`, never the lockfile's recorded names, which would leave out anything new. `PurviewSkillsUpdateMode` and `PRSKL0006` went with the `skills update` step. The re-adds use target batching (`_UpdatePurviewSkillsSource`) so each failure is attributed to its source (`PRSKL0008`, `ErrorAndContinue` so all are named); `-p:PurviewSkillsDryRun=true` prints and runs nothing.

`CheckPurviewSkills`/`FixPurviewSkills` (`EnforcePurviewSkillDirectories`) do nothing unless `PurviewSkillsAgents` names agents. Then the only agent skill directories allowed are those agents', per the `PurviewSkillsAgentDirectory` item group (copied from the CLI's agent table — extend it, don't hard-code), plus `.agents/skills`, the canonical store every agent directory links into. The authored `skills/` folder is protected even though openclaw installs there. Fix deletes links only (never their targets — `RemoveDirectory` on Windows, `unlink` on Unix) and folders left empty; a real file is kept and reported as `PRSKL0015`, because it cannot be told from hand-written content. Note the CLI writes copies, not links, for some agent selections, so those are kept too.

Expand Down
29 changes: 28 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,30 @@ release summarise what the commits recorded rather than what was written at the

## [Unreleased]

## [1.3.2] - 2026-11-09

### Changed

- **`UpdatePurviewSkills` is re-add only.** `skills add` reinstalls every skill it selects, so one
re-add both refreshes the installed skills and adds any a source has gained; the trailing
`skills update -y -p` added nothing and is no longer run.
- **`UpdatePurviewSkills` picks up new skills from every source.** A source no package ships used to be
re-added naming only the skills `skills-lock.json` recorded, so a skill added to that repository
since the last install was never installed. It is now re-added with `--skill "*"`. Package sources
are unchanged: pinned to the package's commit, naming every skill that version ships.
- **The `purview-buildsdk-justfile` skill is now `purview-buildsdk-skills-justfile`.** A repository
that installed the old name keeps it until it is removed: run `npx skills add purview-dev/build-sdk`
for the new one and `npx skills remove purview-buildsdk-justfile` for the old.
- The skills-justfile skill now picks `skills_project` itself: an existing `Justfile` solution variable
first, then a solution path an existing recipe uses, then the repository's only solution file.

### Removed

- `PurviewSkillsUpdateMode`, and `PRSKL0006` with it: there is no `skills update` step left to
schedule. A value still set is ignored.

## [1.3.1] - 2026-11-09

### Added

- **`UpdatePurviewSkills`** re-adds every unique source in `skills-lock.json`, naming only the skills
Expand Down Expand Up @@ -394,7 +418,10 @@ dotnet msbuild <project> -t:VerifyPurviewSkills
- `.editorconfig` values missing test projects.
- Source-generator resolution on pack.

[Unreleased]: https://github.com/purview-dev/build-sdk/compare/v1.2.0...HEAD
[Unreleased]: https://github.com/purview-dev/build-sdk/compare/v1.3.2...HEAD
[1.3.2]: https://github.com/purview-dev/build-sdk/compare/v1.3.1...v1.3.2
[1.3.1]: https://github.com/purview-dev/build-sdk/compare/v1.3.0...v1.3.1
[1.3.0]: https://github.com/purview-dev/build-sdk/compare/v1.2.0...v1.3.0
[1.2.0]: https://github.com/purview-dev/build-sdk/compare/v1.1.0...v1.2.0
[1.1.0]: https://github.com/purview-dev/build-sdk/compare/v1.0.7...v1.1.0
[1.0.7]: https://github.com/purview-dev/build-sdk/compare/v1.0.6...v1.0.7
Expand Down
7 changes: 4 additions & 3 deletions Justfile.skills.just
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,14 @@ skills-list *args:
skills-recommend *args:
dotnet msbuild "{{ skills_project }}" -t:RecommendPurviewSkills -v:n {{ args }}

# Update the agent skills by re-adding every unique source in skills-lock.json, then 'skills update'
# Update the agent skills by re-adding every unique source in skills-lock.json
#
# Skills a referenced package ships are re-added at that package's commit. When PurviewSkillsAgents
# The re-add refreshes installed skills and adds any a source has gained; 'skills update' is never
# run. Skills a referenced package ships are re-added at that package's commit. When PurviewSkillsAgents
# is set, the agent directories it does not select are cleaned up afterwards (FixPurviewSkills);
# when it is not, the skills CLI auto-detects agents and the cleanup does nothing.
#
# just skills-update -p:PurviewSkillsUpdateMode=Always -p:PurviewSkillsDryRun=true
# just skills-update -p:PurviewSkillsDryRun=true
# just skills-update -p:PurviewSkillsRunner=npx -p:PurviewSkillsAgents=universal
#
# Update the agent skills by re-adding every unique source in skills-lock.json
Expand Down
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ A reusable MSBuild SDK NuGet package that delivers standardised .NET project def
"runner": "Microsoft.Testing.Platform"
},
"msbuild-sdks": {
"Purview.BuildSdk": "1.3.1"
"Purview.BuildSdk": "1.3.2"
}
}
```
Expand Down Expand Up @@ -201,7 +201,7 @@ to a low-importance message) and only a copy that still fails after every retry
The bootstrapped `.editorconfig` opens with a version marker:

```editorconfig
# Purview.BuildSdk 1.3.1 - managed file, do not edit
# Purview.BuildSdk 1.3.2 - managed file, do not edit
```

That line is how the SDK recognises a file **it** wrote. When the SDK version changes, a file carrying
Expand Down Expand Up @@ -286,7 +286,7 @@ as a side effect of a restore or a build.
bun x skills add purview-dev/build-sdk # install, the ordinary way
dotnet msbuild <project> -t:RecommendPurviewSkills # what is missing, drifted or unverifiable
dotnet msbuild <project> -t:InstallPurviewSkills # explicit; delegates to the CLI
dotnet msbuild <project> -t:UpdatePurviewSkills # re-add every skills-lock.json source, then 'skills update'
dotnet msbuild <project> -t:UpdatePurviewSkills # re-add every skills-lock.json source: refresh, and add new skills
dotnet msbuild <project> -t:CheckPurviewSkills # only the PurviewSkillsAgents directories exist
dotnet msbuild <project> -t:FixPurviewSkills # remove the CLI's links from any other agent directory
```
Expand Down Expand Up @@ -433,7 +433,6 @@ Non-packable projects (including web applications) default `WarnOnPackingNonPack
| `PurviewSkillsLockFile` | `<repo root>/skills-lock.json` | Overrides where the skills CLI's lockfile is read from. |
| `PurviewSkillsSourceFolder` | `<repo root>/skills` | Repository folder holding authored skills. |
| `PurviewSkillsAgents` | *(empty — the CLI auto-detects)* | Comma-separated agents the skill targets install to, and that recommended commands name. When set, `CheckPurviewSkills`/`FixPurviewSkills` allow only those agents' skill directories. |
| `PurviewSkillsUpdateMode` | `Auto` | When `UpdatePurviewSkills` runs `skills update`: `Auto` (only when `skills-lock.json` changed), `Always` or `Never`. |
| `PurviewSkillsDryRun` | `false` | When `true`, `InstallPurviewSkills` and `UpdatePurviewSkills` print the CLI commands without running them. |
| `PurviewSkillsRunner` | `bun` | Package runner used to launch the skills CLI (`bun`, `npx`, `bunx`, `pnpm`, `yarn`, `deno`, `skills`, or any other). |
| `PurviewSkillsRunnerCandidates` | `bun;npx;bunx;pnpm;yarn;deno` | Runners probed on `PATH` after `PurviewSkillsRunner`. |
Expand Down Expand Up @@ -537,7 +536,6 @@ The SDK now exports its properties via `CompilerVisibleProperty`, so analyzers a
| `PurviewSkillsLockFile` | Where the skills CLI's `skills-lock.json` is read from (default `<repo root>/skills-lock.json`). |
| `PurviewSkillsSourceFolder` | Repository folder holding authored agent skills (default `<repo root>/skills`). |
| `PurviewSkillsAgents` | Comma-separated agents the skill targets install to (default empty: the CLI auto-detects). |
| `PurviewSkillsUpdateMode` | When `UpdatePurviewSkills` runs `skills update`: `Auto` (default), `Always` or `Never`. |
| `PurviewSkillsDryRun` | When `true`, `InstallPurviewSkills` and `UpdatePurviewSkills` print commands without running them. |
| `PurviewSkillsRunner` | Package runner used to launch the skills CLI (default `bun`; also `npx`, `bunx`, `pnpm`, `yarn`, `deno`, `skills`). |
| `PurviewSkillsRunnerCandidates` | Runners probed on `PATH` after `PurviewSkillsRunner` (default `bun;npx;bunx;pnpm;yarn;deno`). |
Expand Down
37 changes: 19 additions & 18 deletions docs/wiki/Agent-Skills.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ because somebody named it.
| `RecommendPurviewSkills` | Reports the state. Never fails a build. |
| `VerifyPurviewSkills` | The same report, escalating `PRSKL0010`/`PRSKL0011` to an error. The CI gate. |
| `InstallPurviewSkills` | Installs every skill the restored packages ship, pinned to each package's commit, via the skills CLI. |
| `UpdatePurviewSkills` | Re-adds every source in `skills-lock.json` — package skills at their package's commit — then runs `skills update`. See [Updating](#updating). |
| `UpdatePurviewSkills` | Re-adds every source in `skills-lock.json` — package skills at their package's commit — refreshing installed skills and adding new ones. See [Updating](#updating). |
| `CheckPurviewSkills` | Fails when an agent skill directory exists for an agent `PurviewSkillsAgents` does not name. See [Choosing agents](#choosing-agents). |
| `FixPurviewSkills` | Removes the CLI's links from those directories, keeping and reporting anything real. |
| `ListPurviewSkills` | Lists what the restored packages ship. Installs nothing. |
Expand All @@ -183,7 +183,6 @@ A correctly installed set produces no output at all from either reporting target
| -- | -- | -- |
| `PurviewSkillsLockFile` | `<repo root>/skills-lock.json` | Overrides where the CLI's lockfile is read from. |
| `PurviewSkillsAgents` | *(empty — the CLI auto-detects)* | Agents the skill targets install to and recommended commands name; when set, the only agent skill directories `CheckPurviewSkills` allows. |
| `PurviewSkillsUpdateMode` | `Auto` | When `UpdatePurviewSkills` runs `skills update`: `Auto` (only when the lockfile changed), `Always` or `Never`. |
| `PurviewSkillsDryRun` | `false` | Print the install and update commands without running them. |
| `PurviewSkillsRunner` | `bun` | Package runner used to launch the CLI. |
| `PurviewSkillsRunnerCandidates` | `bun;npx;bunx;pnpm;yarn;deno` | Probed in order after `PurviewSkillsRunner`. |
Expand Down Expand Up @@ -219,9 +218,9 @@ bun x skills add "purview-dev/purview-example#0123456789abcdef0123456789abcdef01
--skill "purview-alpha" -y
```

A bare re-add or `bun x skills update` is only right for skills no package version speaks for.
`UpdatePurviewSkills` does both, but re-adds a package's skills at that package's commit first — and
`skills update` re-fetches each entry at the ref the lockfile records, so it does not undo the pin.
A re-add at latest is only right for skills no package version speaks for. `UpdatePurviewSkills`
re-adds those at latest and a package's skills at that package's commit, and never runs
`skills update`.

> Note the repeated `--skill` flag. The CLI does not split a comma-separated value: given one, it
> matches nothing and reports "No matching skills found".
Expand Down Expand Up @@ -255,7 +254,7 @@ Installation is **explicit**. None of these targets has `BeforeTargets`/`AfterTa
```bash
dotnet msbuild <project> -t:ListPurviewSkills # diagnostics only, installs nothing
dotnet msbuild <project> -t:InstallPurviewSkills # delegates to the skills CLI
dotnet msbuild <project> -t:UpdatePurviewSkills # re-add every lockfile source, then 'skills update'
dotnet msbuild <project> -t:UpdatePurviewSkills # re-add every lockfile source: refresh, and add new skills
dotnet msbuild <project> -t:CheckPurviewSkills # only the PurviewSkillsAgents directories exist
dotnet msbuild <project> -t:FixPurviewSkills # remove the CLI's links from any other agent directory
```
Expand All @@ -269,14 +268,14 @@ however many projects it holds, because every project hands the work to the same
project and MSBuild's result cache runs it once. Package resolution reads every project in the
solution, so a package only a test project references is still found; a single project sees only its
own packages. For `just` recipes, see the
[`purview-buildsdk-justfile` skill](../../skills/purview-buildsdk-justfile/SKILL.md).
[`purview-buildsdk-skills-justfile` skill](../../skills/purview-buildsdk-skills-justfile/SKILL.md).

`InstallPurviewSkills` shells out to the CLI rather than reimplementing it, because the CLI owns the
agent-specific destinations and their discovery conventions — which differ per agent and change
independently of this SDK — and owns `skills-lock.json`.

`InstallPurviewSkills` installs every skill the restored packages ship, not only the missing ones.
Re-running it is idempotent: the CLI skips a skill already installed from the same source and ref.
Re-running it is safe: the CLI reinstalls each skill it is given, replacing the installed copy.

### Updating

Expand All @@ -286,21 +285,23 @@ dotnet msbuild <project> -t:RecommendPurviewSkills # optional: shows PRSKL0011
dotnet msbuild <project> -t:UpdatePurviewSkills
```

`UpdatePurviewSkills` reads `skills-lock.json` and re-adds each unique source once, naming only the
skills the lockfile records for it — an update never installs a skill nobody asked for:
`UpdatePurviewSkills` reads `skills-lock.json` and re-adds each unique source once. It updates with
`skills add` rather than `skills update`, so a skill a source has gained since the last install is
added as well as the installed ones refreshed:

| Source | Re-added as |
| -- | -- |
| shipped by a restored package | `<owner/repo>#<commit>` — the commit that package version was built from, the same pinned add `PRSKL0011` recommends |
| anything else | `<source>` — its latest |
| shipped by a restored package | `<owner/repo>#<commit>`, naming every skill that package version ships — the commit it was built from, the same pinned add `PRSKL0011` recommends |
| anything else | `<source> --skill "*"` — its latest, with every skill it has |

Then it runs `skills update -y -p` according to `PurviewSkillsUpdateMode`: `Auto` (default) only when
the re-adds changed the lockfile, `Always`, or `Never`. Every source is attempted even when one fails;
each failure is named as `PRSKL0008`, and `skills update` is skipped. No lockfile is `PRSKL0007` —
That is the whole update. `skills add` reinstalls every skill it selects, so one re-add refreshes the
installed skills and adds the new ones; `skills update` would only re-fetch what the lockfile
already lists, and is never run. Every source is attempted even when one fails, and each failure is
named as `PRSKL0008`. No lockfile is `PRSKL0007` —
install first. A CI job can then call `-t:VerifyPurviewSkills` to confirm nothing is left drifted.

`InstallPurviewSkills` is also enough to move package skills to a new package version: it re-adds
each at its package's commit, and the CLI skips one already at that ref.
each at its package's commit.

### Choosing agents

Expand Down Expand Up @@ -563,9 +564,9 @@ Verified against the `skills` CLI v1.
| `PRSKL0003` | The repository root could not be resolved, so there is nowhere correct to install |
| `PRSKL0004` | No package runner was found on `PATH` |
| `PRSKL0005` | An authored skill is malformed |
| `PRSKL0006` | `PurviewSkillsUpdateMode` is not `Auto`, `Always` or `Never` |
| `PRSKL0006` | Retired, with `PurviewSkillsUpdateMode`: update no longer runs `skills update` |
| `PRSKL0007` | `UpdatePurviewSkills` found no `skills-lock.json` to update from |
| `PRSKL0008` | Re-adding a lockfile source failed; `skills update` was skipped |
| `PRSKL0008` | Re-adding a lockfile source failed |
| `PRSKL0009` | Install, update or fix was pulled into a build, a restore or a design-time build |
| `PRSKL0010` | Skills a referenced package ships are not installed |
| `PRSKL0011` | Installed skills are pinned to a different ref than the referenced package |
Expand Down
Loading
Loading