Skip to content

Commit 838d912

Browse files
Make external-reference-check a reusable workflow for federated repos (#79)
1 parent acd5fe9 commit 838d912

4 files changed

Lines changed: 145 additions & 13 deletions

File tree

.github/workflows/external-reference-check.yml

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,25 @@ on:
2121
# Mondays at 12:00 UTC. Catches link rot in unchanged content.
2222
- cron: "0 12 * * 1"
2323
workflow_dispatch:
24+
# Lets OTHER repos reuse this exact check instead of copying it, so the
25+
# logic never drifts. A consumer adds a ~10-line caller workflow:
26+
#
27+
# jobs:
28+
# external-references:
29+
# uses: amd/skills/.github/workflows/external-reference-check.yml@main
30+
# permissions:
31+
# contents: read
32+
# issues: write
33+
#
34+
# The lychee config is NOT configurable: callers always use the canonical
35+
# .github/lychee.toml from amd/skills (pinned to the same commit as this
36+
# workflow), so neither the logic nor the config can drift.
37+
workflow_call:
38+
inputs:
39+
markdown_glob:
40+
description: "Glob of markdown files to check, relative to the caller repo root."
41+
type: string
42+
default: "./**/*.md"
2443

2544
permissions:
2645
contents: read
@@ -34,11 +53,44 @@ jobs:
3453
- name: Check out repository
3554
uses: actions/checkout@v4
3655

56+
# The lychee config always comes from amd/skills so it can never drift.
57+
# When this repo runs the check on itself, the working-tree copy is used
58+
# (so PRs that edit the config are tested against their own changes).
59+
# When another repo calls this workflow, the canonical config is fetched
60+
# from amd/skills at the SAME commit as this workflow file
61+
# (github.job_workflow_sha), keeping logic and config in lockstep.
62+
# Sparse-checkout grabs only the config file so its markdown can't
63+
# pollute the scan.
64+
- name: Fetch canonical lychee config
65+
if: ${{ github.repository != 'amd/skills' }}
66+
uses: actions/checkout@v4
67+
with:
68+
repository: amd/skills
69+
ref: ${{ github.job_workflow_sha || 'main' }}
70+
path: .external-reference-check-config
71+
sparse-checkout: |
72+
.github/lychee.toml
73+
sparse-checkout-cone-mode: false
74+
persist-credentials: false
75+
76+
- name: Resolve lychee config path
77+
id: cfg
78+
shell: bash
79+
env:
80+
IS_CANONICAL: ${{ github.repository == 'amd/skills' }}
81+
run: |
82+
set -euo pipefail
83+
if [ "${IS_CANONICAL}" = "true" ]; then
84+
echo "path=.github/lychee.toml" >> "$GITHUB_OUTPUT"
85+
else
86+
echo "path=.external-reference-check-config/.github/lychee.toml" >> "$GITHUB_OUTPUT"
87+
fi
88+
3789
- name: Check external references
3890
id: lychee
3991
uses: lycheeverse/lychee-action@v2
4092
with:
41-
args: --config .github/lychee.toml --no-progress "./**/*.md"
93+
args: --config ${{ steps.cfg.outputs.path }} --no-progress "${{ inputs.markdown_glob || './**/*.md' }}"
4294
# Fail the workflow on PR and manual runs so broken external
4395
# references show up as a red check (mark this workflow as
4496
# not-required in branch protection if you don't want it to

CONTRIBUTING.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,17 @@ Best for cross-cutting skills that do not have a natural product home.
2929
```
3030
8. Open a pull request. The `validate` GitHub Actions workflow runs `./.github/scripts/check.sh` and must pass before merge. See [Validating locally](#validating-locally) for the full set of enforced rules.
3131

32-
### Path B: Skills authored in a product repository
32+
### Path B: Skills authored in a product repository (federation)
3333

34-
Best for skills that should ship and version with a product (HIP, MIGraphX, Ryzen AI, Lemonade, etc.).
34+
Best for skills that should ship and version with a product (HIP, MIGraphX, Ryzen AI, Lemonade, etc.). Your repo stays the source of truth and the catalog vendors a pinned copy. This is called **federation**, and the full walkthrough lives in [docs/federating-your-repo.md](docs/federating-your-repo.md).
3535

36-
1. Add the skill folder to your product repository; a common location is `.agents/skills/<skill-name>/`.
37-
2. Open a pull request here that adds (or extends) an entry in [`.github/scripts/sources.yml`](.github/scripts/sources.yml) — the master list — naming your repo, a pinned ref, the sub-path that holds skill folders, and your skill's folder name.
38-
3. Once the catalog change merges, dispatch the **Import external skills** workflow from the Actions tab. It shallow-clones your repo at the pinned ref, vendors the skill into `skills/<name>/`, updates `.claude-plugin/marketplace.json`, and opens a follow-up pull request. Validation then runs against the same rules as in-repo skills before merge.
36+
The short version:
37+
38+
1. Keep each skill as a folder with a valid `SKILL.md` and `skill-card.md` in your AMD-owned repo (a common location is `skills/` or `.agents/skills/<skill-name>/`).
39+
2. Add (or extend) an entry in [`.github/scripts/sources.yml`](.github/scripts/sources.yml) — the master list — naming your repo, a pinned ref, the sub-path that holds skill folders, and each skill's folder name.
40+
3. Vendor the skills and refresh the manifests locally, then open a pull request here for review. Validation runs against the same rules as in-repo skills before merge.
41+
42+
See [docs/federating-your-repo.md](docs/federating-your-repo.md) for the exact `sources.yml` schema, the import commands, and how to run the catalog's checks in your own repo.
3943

4044
## Is this task a good fit for a skill?
4145

docs/federating-your-repo.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Federate Your Repo Into the Catalog
2+
3+
How to list skills that live in **your own AMD repo** in this catalog. Your repo
4+
stays the source of truth; the catalog vendors a pinned copy.
5+
6+
This is the detailed version of **Path B** in
7+
[CONTRIBUTING.md](../CONTRIBUTING.md#path-b-skills-authored-in-a-product-repository-federation).
8+
Start there for an overview of how it compares to authoring skills directly in
9+
this repo.
10+
11+
> **Eligibility: AMD-owned repositories only.** The source `repo` must be under
12+
> an AMD GitHub org (e.g. `AMD-AGI/...`). Non-AMD repos are not accepted.
13+
14+
## Prerequisites
15+
16+
- Each skill is a folder with a valid `SKILL.md` and `skill-card.md`.
17+
See [CONTRIBUTING.md](../CONTRIBUTING.md) and [skill-cards.md](skill-cards.md).
18+
- Skills live in a known directory in your repo (e.g. `skills/`).
19+
- Pick a branch to track (e.g. `main` or a release branch).
20+
21+
## Add your source
22+
23+
Edit [`.github/scripts/sources.yml`](../.github/scripts/sources.yml) and append an entry:
24+
25+
```yaml
26+
sources:
27+
- name: amd-myproject # kebab-case source id
28+
repo: AMD-Org/MyProject # must be AMD-owned
29+
ref: main # branch to track (e.g. main or a release branch)
30+
path: skills # dir in your repo holding the skill folders
31+
license: MIT # SPDX id, carried into the marker file
32+
skills:
33+
- name: my-skill # folder name in your repo
34+
as: myproject-my-skill # local catalog name: <project>-<skill>
35+
```
36+
37+
Use `as:` to namespace skills as `<project>-<skill>` so catalog names stay unique.
38+
39+
## Import
40+
41+
Run the import scripts locally (they read `sources.yml` from your working tree),
42+
then open a PR for review.
43+
44+
1. Vendor the skills and refresh the manifests:
45+
46+
```bash
47+
uv run .github/scripts/import_external_skills.py # vendor into skills/<name>/
48+
uv run .github/scripts/generate_cursor_marketplace.py
49+
./.github/scripts/check.sh # validate
50+
```
51+
52+
2. Commit `skills/**`, `.github/scripts/sources.yml`, and the manifests.
53+
3. Open a PR; a maintainer reviews and merges once CI passes.
54+
55+
## Catch failures before nightly
56+
57+
The catalog runs checks against your skills. Run the **same** checks in your own
58+
repo by calling them as reusable workflows, so you catch breakage during normal
59+
development instead of in the catalog's nightly run. The logic and config live in
60+
`amd/skills`, so green in your repo means green in the catalog — and you never copy
61+
or maintain the check yourself.
62+
63+
Add a caller workflow to your repo (e.g. `.github/workflows/skills-checks.yml`):
64+
65+
```yaml
66+
name: skills-checks
67+
on:
68+
pull_request:
69+
workflow_dispatch:
70+
jobs:
71+
external-references:
72+
uses: amd/skills/.github/workflows/external-reference-check.yml@main
73+
permissions:
74+
contents: read
75+
issues: write
76+
```
77+
78+
## Update or remove
79+
80+
Automatic refresh and pruning will soon be enabled through nightly workflows.
81+
82+
Never hand-edit vendored skills under `skills/`; changes must come from your repo
83+
via re-import, or they'll be overwritten.

eval/behavioral/harness.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,6 @@ def check_api_reachable(model: str | None = DEFAULT_MODEL, timeout: int = 60) ->
101101
if model:
102102
cmd += ["--model", model]
103103

104-
# Prompt goes over stdin (see `_run_agent` for why) -- consistent here even
105-
# though this one is single-line.
106104
try:
107105
proc = subprocess.run(
108106
cmd, capture_output=True, text=True, encoding="utf-8",
@@ -147,11 +145,6 @@ def _run_agent(prompt_text: str, workspace: Path, model: str | None, effort: str
147145
if effort:
148146
cmd += ["--effort", effort]
149147

150-
# Pass the prompt over stdin rather than as an argv string. On Windows, when
151-
# `claude` resolves to a .cmd/.ps1 shim, a multi-line command-line argument
152-
# is re-parsed by cmd.exe/PowerShell and truncated at the first newline.
153-
# stdin is a raw byte stream and is immune to that on all platforms, so
154-
# multi-line test prompts stay intact.
155148
proc = subprocess.run(
156149
cmd, cwd=str(workspace), capture_output=True, text=True,
157150
encoding="utf-8", input=prompt_text, env=_claude_env(),

0 commit comments

Comments
 (0)