Skip to content

Commit 2729cee

Browse files
authored
Merge pull request #6 from Clawdi-AI/feat/agent-plugin-source-recipes
feat(v2): package pinned upstream Agent Plugins
2 parents 13cab68 + c69a5e6 commit 2729cee

19 files changed

Lines changed: 1446 additions & 50 deletions
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Publish Agent Plugin Artifacts
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- "v2/source-packages/**"
8+
- "v2/scripts/source_package.py"
9+
- "v2/scripts/plugin_package.py"
10+
- "v2/scripts/plugin_validation.py"
11+
- "v2/scripts/skill_validation.py"
12+
- "v2/schemas/**"
13+
workflow_dispatch:
14+
15+
permissions:
16+
contents: write
17+
18+
concurrency:
19+
group: agent-plugin-artifacts
20+
cancel-in-progress: false
21+
22+
jobs:
23+
publish:
24+
if: github.ref == 'refs/heads/main'
25+
runs-on: ubuntu-latest
26+
steps:
27+
- uses: actions/checkout@v4
28+
- uses: actions/setup-python@v5
29+
with:
30+
python-version: "3.12"
31+
- name: Install validation dependencies
32+
run: python -m pip install --disable-pip-version-check -r v2/requirements.txt
33+
- name: Build and verify artifacts
34+
run: python v2/scripts/source_package.py --check --artifacts "$RUNNER_TEMP/artifacts"
35+
- name: Publish immutable release assets
36+
env:
37+
GH_TOKEN: ${{ github.token }}
38+
run: |
39+
set -euo pipefail
40+
for release in v2/source-packages/*/release.json; do
41+
url=$(jq -r '.source.url' "$release")
42+
expected=$(jq -r '.source.archiveDigest | sub("^sha256:"; "")' "$release")
43+
tag=$(python -c 'import sys, urllib.parse; print(urllib.parse.unquote(sys.argv[1].split("/releases/download/", 1)[1].split("/", 1)[0]))' "$url")
44+
asset=$(python -c 'import sys, urllib.parse; print(urllib.parse.unquote(sys.argv[1].rsplit("/", 1)[1]))' "$url")
45+
artifact="$RUNNER_TEMP/artifacts/$asset"
46+
actual=$(sha256sum "$artifact" | cut -d ' ' -f 1)
47+
test "$actual" = "$expected"
48+
49+
existing="$RUNNER_TEMP/existing-$asset"
50+
if gh release download "$tag" --pattern "$asset" --output "$existing" 2>/dev/null; then
51+
test "$(sha256sum "$existing" | cut -d ' ' -f 1)" = "$expected"
52+
continue
53+
fi
54+
if gh release view "$tag" >/dev/null 2>&1; then
55+
gh release upload "$tag" "$artifact"
56+
else
57+
gh release create "$tag" "$artifact" --title "$tag" --notes "Generated from pinned upstream sources at $GITHUB_SHA."
58+
fi
59+
done

.github/workflows/validate.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ jobs:
2020
run: python -m pip install --disable-pip-version-check -r v2/requirements.txt
2121
- name: Test Agent v2 Store validation
2222
run: python -m unittest discover -s v2/tests -v
23+
- name: Rebuild pinned Agent Plugin sources
24+
run: python v2/scripts/source_package.py --check
2325
- name: Validate Agent v2 Store
2426
run: python v2/scripts/validate.py
2527
- name: Enforce published Agent v2 package immutability

v2/CONTRIBUTING.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Contributing to the Agent v2 Store
22

3-
Keep authored package data inside one `v2/plugins/<plugin-key>/` package. Use
3+
Keep authored package data inside one `v2/plugins/<plugin-key>/` package. For
4+
approved upstream Skills, use a closed recipe under `v2/source-packages/` and
5+
pin full 40-hex GitHub commits; do not use branches, tags, submodules, symlinks,
6+
or runtime downloads. Use
47
top-level `plugin.json.keywords` for search and discovery; do not duplicate it
58
with extension tags. Never edit `v2/catalog.json` by hand: regenerate its
69
normalized projection after package changes. Include licenses and attribution
@@ -10,13 +13,14 @@ Before opening a pull request, run:
1013

1114
```bash
1215
python3 -m pip install -r v2/requirements.txt
16+
python3 v2/scripts/source_package.py --check
1317
python3 v2/scripts/catalog.py --write
1418
python3 v2/scripts/validate.py
1519
python3 -m unittest discover -s v2/tests -v
1620
```
1721

18-
Review the reported `sha256-tree-v1` digest when package contents or executable
19-
modes change. Once a `name` and `version` appear in the baseline catalog, their
20-
digest is immutable; bump `plugin.json.version` before publishing changed
21-
bytes. Validation does not replace dependency, license, or runtime security
22-
review.
22+
Review both reported digests when source mappings, package contents, or
23+
executable modes change. Once a `name` and `version` appear in the baseline
24+
catalog, their source and digest are immutable; bump `plugin.json.version` and
25+
the release tag/asset before publishing changed bytes. Validation does not
26+
replace license, provenance, dependency, or runtime security review.

v2/README.md

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,23 @@ non-secret. For protected remote MCP servers, standard MCP Authorization is
9494
performed by the MCP client and managed by its host/runtime, not declared as
9595
Store package authentication metadata.
9696

97+
## Source-built packages
98+
99+
Third-party Skills may be packaged from immutable upstream GitHub commits
100+
without checking their files into this branch. A closed recipe under
101+
`v2/source-packages/<name>/` maps selected upstream directories into a standard,
102+
self-contained Agent Plugin. CI downloads the pinned commit, rejects unsafe
103+
archive entries, validates the complete package, and reproduces a deterministic
104+
`.tar.gz` artifact. `release.json` binds its GitHub Release URL, archive SHA-256,
105+
package `sha256-tree-v1` digest, and catalog projection.
106+
107+
Published release assets are immutable. The publish workflow creates a missing
108+
asset, treats an existing byte-identical asset as a no-op, and fails rather than
109+
overwriting different bytes. Runtime clients verify both digests before native
110+
installation. Upstream source files exist in the release artifact because Agent
111+
Plugins 1.0.0 packages must be self-contained; they are not retained in Store
112+
main or a developer checkout.
113+
97114
## Generated Store index
98115

99116
`v2/catalog.json` is a Clawdi Store index, not an Agent Plugins standard field.
@@ -103,28 +120,26 @@ It is generated only from packages that pass the validation above:
103120
python3 v2/scripts/catalog.py --write
104121
```
105122

106-
The closed `schemaVersion: 1` entry is a normalized listing and resolution
123+
The closed `schemaVersion: 2` entry is a normalized listing and resolution
107124
projection. It contains package `name` and `version`; `displayName`, optional
108125
`description` and `publisher`, `category`, standard `keywords`, and `languages`;
109-
declared `runtimes`; `path` and optional `icon`; the `sha256-tree-v1` `digest`;
110-
`hasConfiguration`; and a closed `components` summary. `components.skills`
126+
declared `runtimes`; a closed `source` and optional in-Store `icon`; the
127+
`sha256-tree-v1` `digest`; and a closed `components` summary. `components.skills`
111128
contains exact Skill names, while `components.mcpServers` maps exact server
112129
names to declared `stdio`, `streamable-http`, or `sse` transports. It contains
113130
no Skill bodies or descriptions and no MCP URLs, headers, commands, or
114131
configuration data. Catalog-facing human strings and array items cannot
115132
contain ASCII control characters or DEL.
116133

117-
`hasConfiguration` is retained for catalog schema compatibility and is always
118-
`false`. Packages cannot declare `extensions["ai.clawdi"].configuration`.
134+
Packages cannot declare `extensions["ai.clawdi"].configuration`.
119135

120-
The index contains no Git commit. `path` is resolved relative to the directory
121-
containing `v2/catalog.json`, so `./plugins/example-plugin` selects
122-
`v2/plugins/example-plugin` in the same snapshot. A consumer resolves an
123-
external Store commit, verifies `digest`, and binds the install to that commit
124-
plus digest. The index exposes one current published version per plugin; it is
125-
not a multi-version registry. Existing installs remain pinned to their original
126-
commit and digest after a newer version replaces or removes the listing; the
127-
package bytes remain fetchable from that historical commit.
136+
For authored packages, `source.type: "store"` contains a path relative to the
137+
directory containing `v2/catalog.json`; consumers bind it to the resolved Store
138+
commit. For source-built packages, `source.type: "github-release"` contains a
139+
canonical asset URL and archive SHA-256. Consumers persist the complete source
140+
object and the tree digest. The index exposes one current published version per
141+
plugin; it is not a multi-version registry. Existing installs remain pinned to
142+
their original source and digests after a listing changes or is removed.
128143

129144
CI rejects generated-file drift. Its separate baseline check also rejects a
130145
version regression or a changed digest for a `name` and `version` already
@@ -138,13 +153,15 @@ Run from the repository root:
138153

139154
```bash
140155
python3 -m pip install -r v2/requirements.txt
156+
python3 v2/scripts/source_package.py --check
141157
python3 v2/scripts/catalog.py --write
142158
python3 v2/scripts/validate.py
143159
python3 -m unittest discover -s v2/tests -v
144160
```
145161

146-
Validation is offline and scans only `v2/plugins`, then compares the checked-in
147-
catalog with the deterministic generated bytes. The canonical upstream
162+
Local-package validation is offline. Source-package reproduction downloads only
163+
the immutable GitHub commits declared by recipes, then compares generated locks
164+
and catalog bytes. The canonical upstream
148165
schemas are vendored under `v2/schemas/` for source review and audit. The
149166
validator performs explicit validation of the supported 1.0.0 contract; it is
150167
not a general JSON Schema evaluator.

v2/SECURITY.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,10 @@ Review bundled executables and dependencies before publishing. Plugin packages
1111
cannot declare installers, install hooks, OAuth registration, trust state, or
1212
other privileged author-controlled behavior. Follow the repository root
1313
`SECURITY.md` for private vulnerability reporting and incident response.
14+
15+
Source-package recipes must pin full GitHub commit IDs. Generated archives
16+
reject links, special files, path escapes, collisions, and unbounded input, and
17+
release assets are never overwritten. Review upstream licenses and source
18+
changes before updating a pin. A package's remote MCP URL is public package
19+
configuration; OAuth tokens remain client-managed and are not baked into the
20+
artifact or Store catalog.

v2/catalog.json

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,97 @@
11
{
2-
"plugins": [],
3-
"schemaVersion": 1
2+
"plugins": [
3+
{
4+
"category": "developer-tools",
5+
"components": {
6+
"mcpServers": {},
7+
"skills": [
8+
"cetus-aggregator",
9+
"cetus-clmm",
10+
"cetus-dlmm"
11+
]
12+
},
13+
"description": "Cetus Protocol development guidance for swaps, CLMM, and DLMM on Sui.",
14+
"digest": "sha256-tree-v1:015fd5cb641dae43479e500e65f0582831f81051ccc7c26579137e38ee8ec721",
15+
"displayName": "Cetus Protocol",
16+
"keywords": [
17+
"cetus",
18+
"sui",
19+
"defi",
20+
"liquidity",
21+
"swaps"
22+
],
23+
"languages": [
24+
"en"
25+
],
26+
"name": "cetus",
27+
"publisher": "Cetus Protocol",
28+
"runtimes": [
29+
"openclaw",
30+
"hermes"
31+
],
32+
"source": {
33+
"archiveDigest": "sha256:10974bca87f9045c9fc68a6af4b2fff16304d806b6cb4754fe75c54d1b105b72",
34+
"type": "github-release",
35+
"url": "https://github.com/Clawdi-AI/store/releases/download/agent-plugin-cetus-v0.1.0/cetus-0.1.0.tar.gz"
36+
},
37+
"version": "0.1.0"
38+
},
39+
{
40+
"category": "developer-tools",
41+
"components": {
42+
"mcpServers": {
43+
"sui-docs": "streamable-http"
44+
},
45+
"skills": [
46+
"accessing-data",
47+
"composable-move-functions",
48+
"frontend-apps",
49+
"generate-sui-agent-config",
50+
"modern-move-syntax",
51+
"move-unit-testing",
52+
"naming-conventions",
53+
"ptbs",
54+
"sui-build",
55+
"sui-cli",
56+
"sui-client",
57+
"sui-install",
58+
"sui-move",
59+
"sui-move-project",
60+
"sui-object-model",
61+
"sui-overview",
62+
"sui-publish",
63+
"sui-sdks",
64+
"walrus-sites",
65+
"walrus-sites-portal",
66+
"walrus-sites-publishing"
67+
]
68+
},
69+
"description": "Official Sui development guidance and documentation access for coding agents.",
70+
"digest": "sha256-tree-v1:c4dda94ccbb861177ce8029221824b1e67dc71a5af33d9d9e14f84561257f269",
71+
"displayName": "Sui Development",
72+
"keywords": [
73+
"sui",
74+
"move",
75+
"blockchain",
76+
"smart-contracts",
77+
"sdk"
78+
],
79+
"languages": [
80+
"en"
81+
],
82+
"name": "sui",
83+
"publisher": "Mysten Labs",
84+
"runtimes": [
85+
"openclaw",
86+
"hermes"
87+
],
88+
"source": {
89+
"archiveDigest": "sha256:a9364b27efea274693e0ef7f7a5b56974f020c261876aade22f64df6e8975f24",
90+
"type": "github-release",
91+
"url": "https://github.com/Clawdi-AI/store/releases/download/agent-plugin-sui-v0.1.0/sui-0.1.0.tar.gz"
92+
},
93+
"version": "0.1.0"
94+
}
95+
],
96+
"schemaVersion": 2
497
}

0 commit comments

Comments
 (0)