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
182 changes: 182 additions & 0 deletions .agents/skills/add-catalogue-project/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
---
name: add-catalogue-project
description: Use when adding a repository to the Purview-Dev website catalogue — recon the repo, author the catalogue record (docs, packages, tags, use cases), integrate it across the catalogue/docs/releases surfaces, and prove it with the validation pipeline.
category: purview-dev-website
roles:
- catalogue
- docs
- integration
tags:
- projects-yml
- astro
- starlight
- documentation
---

# add-catalogue-project Skill

Use this skill when a repository must be added to (or promoted within) the Purview-Dev website.

Related: `add-project-intake`, `project-manifest-reference`, `docs-aggregation-rules`,
`use-case-authoring`, `github-repo-metadata`, `site-validation-loop`.

## Step 0 — decide the target collection

| Situation | Where it goes |
| --- | --- |
| Repository is owned by the `purview-dev` organisation | `projects:` |
| Project the organisation contributes to but does not own (for example `likec4/likec4`) | `externalProjects:` |

Only `projects:` entries get a `/projects/<id>/` page, documentation aggregation, LLM bundles and
release data. `externalProjects:` entries are link-out cards on `/projects/` and must never point at
a `purview-dev` repository.

## Step 1 — recon the repository (never guess)

```shell
# Metadata: description, topics, archived, default branch, discussions, homepage
gh api repos/<owner>/<repo> --jq '{description, topics, archived, default_branch, has_discussions, homepage}'

# Docs layout: does docs/ exist, is it a mirror of the wiki, is there a _Sidebar.md?
gh api "repos/<owner>/<repo>/git/trees/main?recursive=1" --jq '.tree[].path'
gh api "repos/<owner>/<repo>/contents/README.md" -H 'Accept: application/vnd.github.raw'

# Project conventions: build type, agent guidance, licensing
gh api "repos/<owner>/<repo>/contents/purview-build.json" -H 'Accept: application/vnd.github.raw'

# Release channel and tag shape
gh api "repos/<owner>/<repo>/releases?per_page=10" --jq '.[] | {tag_name, prerelease, published_at}'

# Packages: confirm each id exists and see its channel (replace the id)
curl.exe -s "https://api.nuget.org/v3-flatcontainer/<packageid>/index.json"
# npm packages (skip the NuGet index): the registry document carries versions + dist-tags
curl.exe -s "https://registry.npmjs.org/<scope>%2F<name>"
```

Record, as evidence for the record you are about to write: where the docs live, the exact markdown
file that should be the landing page, the NuGet package ids, the release channel, and the repository
description/topics.

## Step 2 — classify

- `category`: exactly one of `application-framework`, `validation`, `observability`,
`source-generation`, `aspire`, `build-tooling`, `developer-tooling`.
- `status`:
- `archived` when the repository is archived (GitHub `archived: true`).
- `preview` when there is no stable release on the registry the project publishes to.
- `stable` only when a stable (non-prerelease) release exists and is recommended for use.
- `experimental: true` (a flag, not a status value) when the tooling is explicitly an experiment:
no compatibility promise, no production support guarantee. Keep `status` as the honest release
channel alongside it (`preview` for prerelease-only tooling). See ADR 0004; the project page and
every aggregated documentation page then carry an Experimental warning.
- `id`: lowercase `[a-z0-9-]` slug, normally the repository name.
- `name`: display name. **It must slugify to `id` when the project has `docs`** (so the display name
and the `/projects/<id>/` and `/docs/<id>/` URLs agree).
- `order`: pick an unused value (10–80 in tens is the existing convention).

## Step 3 — author the record

Add the entry as `src/src/data/projects/<id>.yml` (see `project-manifest-reference` for every field):

```yaml
- id: <slug>
name: <Display Name>
shortDescription: <one sentence, kept short>
description: >-
<two to four sentences: what it is, what it replaces, what it generates/does>
origin: >-
<why this became reusable tooling>
useWhen: >-
<the situation where it is the right choice>
avoidWhen: >-
<the situation where it is the wrong choice>
repository: purview-dev/<repo>
category: <category>
status: <status>
order: <unused order>
docs:
source: github-path | wiki | readme
path: docs # github-path only
rootPage: Home.md # optional; see docs-aggregation-rules
exclude: [ _Sidebar.md ] # only files the repository actually ships
targetFrameworks: [ net8.0, net9.0 ]
install: nuget | msbuild-sdk | dotnet-tool # NuGet packages only; omit for npm
packages:
- id: <Package.Id.Or.Npm.Name>
registry: nuget | npm # optional; defaults to nuget (ADR 0012)
description: <what this package is for>
primary: true
related: [ <known-project-id> ]
acknowledgments:
- name: <upstream project>
url: https://github.com/<owner>/<repo>
description: <how this project relates to it>
useCases:
- audience: developer
title: <short, concrete scenario title>
scenario: >-
<the situation the reader is in>
code: |
<minimal snippet that shows the idea>
language: csharp
outcome: >-
<what the reader gets back>
evidence: >-
<a fact: before/after, count, generated output, measured property>
docsPage: <slug-of-an-aggregated-page>
```

Every non-archived project needs at least **one** use case with `code` + `language` and an
`evidence` fact (ADR 0002). See `use-case-authoring`.

## Step 4 — fix the upstream metadata (this is where tags come from)

- Set GitHub **topics** on the repository (they become the site's tag chips). See
`github-repo-metadata` for the exact command and the taxonomy guidance.
- The repository description must be genuinely descriptive: it backs the `shortDescription`
fallback and social/`og:` metadata.
- Leave `discussions` unset: the loader detects it from the repository (`hasDiscussions`). Set
`discussions: false` only to opt a repository out, or `true` to force the link.

## Step 5 — integrate and verify

```shell
just data-sync # aggregate docs + refresh release data (cache-first)
just check-projects # deterministic catalogue guard (part of `just validate`)
bun run typecheck && bun run test
just check-generated
just validate # full chain: format, lint, build, link crawl, dist tests
```

Confirm each surface actually lights up:

1. `/projects/` shows the card with the right category/status/tags (tags come from topics).
2. `/projects/<id>/` renders description, use cases, install panel, packages, and related links.
3. `/docs/<id>/` exists with the expected page count and a sidebar topic named after the project.
4. `/projects/<id>/llms.txt` and `/projects/<id>/llms-full.txt` are emitted and linked from
`/llms.txt`.
5. `/use-cases/` lists the new use cases under the right audiences.
6. `/releases/` shows GitHub and registry versions (NuGet or npm) for the declared packages.
7. If a live example page exists at `src/src/pages/examples/<id>.mdx`, `/projects/<id>/` links it as
**Live example** (the page is discovered, not declared).

## Step 6 — report

State: the record added, the recon evidence, the package ids and channels, the docs source and page
count, the checks run with their result, and any `upstream` follow-ups (for example: topics missing,
docs not yet in a `docs/` folder, no stable release yet).

## Pitfalls

- `docs.path` must be a **repository path** (`docs`, `docs/wiki`), never a URL.
- A repository whose wiki is mirrored into `docs/wiki` is plain Markdown: `Home.md` is the hub and
`_Sidebar.md` (the navigation) is the only file that has to be excluded. A wiki that keeps a
different first page keeps `rootPage`; only a page the repository does **not** ship needs excluding,
and a stale pattern (an `index.md` the upstream deleted) is a silent no-op rather than an error.
See `docs-aggregation-rules`.
- Aggregation reads branch `main`. If the repository's default branch is `master`/`develop`, docs
aggregation silently yields nothing — rename or report it.
- The `README.md`-as-index mode (`readme:`) publishes exactly one page and cannot be combined with
`rootPage`.
- Adding a project does not require editing tests: the manifest tests assert `>=` counts, not exact
membership. But keep their expectations true (for example the `>= 8` use-case coverage).
154 changes: 154 additions & 0 deletions .agents/skills/audit-catalogue-projects/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
name: audit-catalogue-projects
description: Use when auditing or repairing the catalogue records under src/src/data/ — the invariant checklist for documentation, stability, metadata, tags, packages, relationships, use cases and ordering, plus the findings report format.
category: purview-dev-website
roles:
- catalogue
- audit
tags:
- projects-yml
- validation
- metadata
---

# audit-catalogue-projects Skill

Use this skill to answer "is every project in the catalogue correct?" with evidence, and to repair
the unambiguous problems.

Related: `project-manifest-reference` (fields and vocabularies), `docs-aggregation-rules`,
`use-case-authoring`, `github-repo-metadata`, `site-validation-loop`.

## Method

1. **Deterministic first.** Run `just check-projects` and `bun run test`. These already enforce the
structural invariants; start from their output rather than re-deriving it.
2. **Then the judgement checks** that no script can make: is the description truthful, is the
category right, is the stability honest, is the use-case evidence real.
3. **Gather live evidence per project** with `gh` and NuGet (commands in `github-repo-metadata`).
4. **Report before repairing.** Produce the findings table, then apply `blocker`/`drift` fixes and
re-run the guards.

## Invariant checklist

### Structure (enforced by `loadProjects()` / `just check-projects`)

- `id` is a lowercase `[a-z0-9-]` slug; `repository` is `purview-dev/<repo>` for `projects:`.
- `related`, `supersedes`, `supersededBy` reference known ids; a superseded project names its
successor and vice versa where the pairing exists.
- Every NuGet package id appears exactly once across the catalogue.
- `order` values are unique integers and the sorted order is the intended presentation order.
- For every project with `docs`, `name` slugifies to exactly `id`.
- Every non-archived project has ≥1 use case; every use case with `code` has `language`.
- Every `docsPage` resolves to a page in `src/.cache/docs/index.json` for that project.
- `externalProjects` never point at a `purview-dev` repository and always have a working `url`.

### Documentation

- `docs.source` matches reality: `github-path` when the repository has a docs folder,
`wiki` when the content lives in the wiki, `readme` only for single-page projects.
- `docs.path` exists **on branch `main`** and contains `.md` files.
- `rootPage` names a page that exists under `docs.path`; when it names a non-index page and a
conventional root page (`index.md`/`Home.md`/`readme.md`) also exists, that conventional page must be
listed in `exclude`.
- `exclude` keeps the navigation files out of the page list: `_Sidebar.md` (and `_Footer.md` for a
`wiki` source). It is a filter over the files the repository ships, so a pattern naming a file that
no longer exists is a no-op, not a warning or a failure.
- The aggregated page count is non-zero and the landing page is the page a reader should land on.
- Archived projects that still declare `docs` are intentional (they are excluded from the portal).
- Documentation is not duplicated here: this repository only holds the mirror.
- Pages moved in the repository's history have a redirect — in its `_redirects.yml` or the entry's
`docs.redirects` (ADR 0013). Diagrams are LikeC4/Mermaid pairs, not ASCII art or Mermaid in a
`text` fence. The consumer assessment script reports both against a clone (below); file the
repository-side fixes as `upstream` items, since they belong in the product repository.

### Stability

- `archived` repository ⇒ `status: archived`.
- No stable NuGet release ⇒ not `stable` (`preview`).
- `experimental: true` is orthogonal to `status`: report `experimental` with `status: stable` as
`drift` (the flag says "no support promise" while the channel says "recommended for use"), and
`experimental` on an archived project as a `blocker` (the schema rejects it outright).
- `stable` ⇒ a stable, listed NuGet release exists and the repository is not archived.
- Deprecated NuGet packages are reported, not silently accepted.
- A project with `packages: []` is intentional: build tooling consumed as a tool/SDK still declares
its package id when one exists.

### Metadata and tags

- Repository description is present, factual, and consistent with `shortDescription`/`description`.
- **Topics are non-empty** — they are the only source of site tags — and follow the lowercase,
hyphenated taxonomy.
- `discussions: true` only when the repository has discussions enabled.
- `homepage`/`url` targets resolve.
- `featured` is used deliberately (a handful of headline projects, not most of the catalogue).

### Packages, frameworks and install

- Each declared package id exists on NuGet and has published versions (the guard checks the release
cache).
- Exactly one `primary` when a project has multiple packages.
- `targetFrameworks` match the package's actual TFMs (`netstandard2.0` for generators/analyzers is
normal). `just check-projects` reports a mismatch as an advisory observation: project-level
frameworks against the union of the runtime packages' published TFMs, package-level frameworks
against that package's own. `netstandard*` is treated as an analyzer/generator target, not a
consumer framework.
- `install` is set only when the package is not a plain NuGet reference: `msbuild-sdk` for
`Purview.BuildSdk`, `dotnet-tool` for `Purview.Build`.

### Use cases

- Coverage across audiences is meaningful for the project's shape (adopter, approver, extender).
- `scenario` describes a situation; `outcome` describes the result; `evidence` is a fact.
- Snippets are short, compile-plausible, and use the right `language`.
- `docsPage` points at the page that actually carries the depth.

## Evidence commands

```shell
# Deterministic guards
just check-projects
bun run test

# Per-project live evidence
gh api repos/purview-dev/<repo> --jq '{description, topics, archived, default_branch, has_discussions, homepage}'
gh api "repos/purview-dev/<repo>/git/trees/main?recursive=1" --jq '[.tree[].path | select(endswith(".md"))]'
gh api "repos/purview-dev/<repo>/releases?per_page=10" --jq '.[] | {tag_name, prerelease}'
curl.exe -s "https://api.nuget.org/v3-flatcontainer/<packageid>/index.json"

# Repository-side integration (docs layout, diagrams, redirects, skills) against a fresh clone
git clone --depth 300 https://github.com/purview-dev/<repo>.git <scratch>/<repo>
node skills/purview-site-assessment/scripts/assess.mjs <scratch>/<repo> --catalogue src/src/data/projects/<id>.yml

# Aggregated result
node -e "const m=require('./src/.cache/docs/index.json');for(const p of m.projects)console.log(p.projectId,p.pages.length)"
```

If `.cache/docs/index.json` or the release cache is stale, run `just data-sync` (live) first so the
evidence and the guards agree.

## Report format

```markdown
| Project | Field | Observed | Expected | Severity | Evidence | Fix |
| --- | --- | --- | --- | --- | --- | --- |
| example-tool | status | stable | preview | drift | no stable NuGet version (flat container: only 1.2.0-prerelease.3) | set status: preview |
| example-tool | — | topics: [] | 6–15 topics | drift | `gh api repos/...` shows an empty topics array | set repository topics |
```

- Severity: `blocker` (schema/build failure or a broken page), `drift` (data contradicts reality),
`polish` (quality), `upstream` (must be fixed in the product repository: missing docs, missing
topics you cannot set, no stable release).
- Close the report with: number of projects audited, checks run, fixes applied, and the items left
for a human.
- Apply only `blocker` and `drift` fixes; never restructure a record or change a category to make a
check pass.

## Guardrails

- Do not add use cases or evidence you cannot trace to the repository or the aggregated docs; report
the gap instead.
- Do not change the schema vocabulary; adding a `status`/`category` value needs an ADR.
- Do not hand-edit the docs mirror or caches to make the audit pass.
- If an audit fix changes a catalogue record, re-run `just check-projects`, `bun run test`, and
`just validate` before reporting completion.
Loading
Loading