Skip to content

Commit 23940ee

Browse files
committed
first commit
0 parents  commit 23940ee

File tree

2 files changed

+309
-0
lines changed

2 files changed

+309
-0
lines changed

.github/workflows/build.yml

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
# Reusable workflow for building and releasing Symposium agent extensions
2+
#
3+
# Builds cross-platform binaries and uploads them to a GitHub release.
4+
# Generates extension.json metadata for the ACP registry.
5+
#
6+
# Usage:
7+
# jobs:
8+
# release:
9+
# permissions:
10+
# contents: write
11+
# uses: symposium-dev/package-agent-extension/.github/workflows/build.yml@v1
12+
# with:
13+
# musl: true
14+
# secrets: inherit
15+
16+
name: Build Agent Extension
17+
18+
on:
19+
workflow_call:
20+
inputs:
21+
manifest:
22+
description: "Path to Cargo.toml (default: ./Cargo.toml)"
23+
type: string
24+
default: "./Cargo.toml"
25+
musl:
26+
description: "Use musl for Linux builds (static linking)"
27+
type: boolean
28+
required: true
29+
extra_args:
30+
description: 'Additional args to append (JSON array, e.g. ["--flag"])'
31+
type: string
32+
default: "[]"
33+
extra_env:
34+
description: 'Additional env vars to merge (JSON object, e.g. {"KEY": "value"})'
35+
type: string
36+
default: "{}"
37+
38+
jobs:
39+
metadata:
40+
name: Extract Metadata
41+
runs-on: ubuntu-latest
42+
outputs:
43+
name: ${{ steps.meta.outputs.name }}
44+
version: ${{ steps.meta.outputs.version }}
45+
binary: ${{ steps.meta.outputs.binary }}
46+
description: ${{ steps.meta.outputs.description }}
47+
args: ${{ steps.meta.outputs.args }}
48+
env: ${{ steps.meta.outputs.env }}
49+
steps:
50+
- uses: actions/checkout@v4
51+
52+
- name: Extract package metadata
53+
id: meta
54+
shell: bash
55+
run: |
56+
METADATA=$(cargo metadata --format-version=1 --no-deps --manifest-path ${{ inputs.manifest }})
57+
58+
# Core package info
59+
echo "name=$(echo "$METADATA" | jq -r '.packages[0].name')" >> $GITHUB_OUTPUT
60+
echo "version=$(echo "$METADATA" | jq -r '.packages[0].version')" >> $GITHUB_OUTPUT
61+
echo "description=$(echo "$METADATA" | jq -r '.packages[0].description // ""')" >> $GITHUB_OUTPUT
62+
63+
# Symposium-specific metadata (falls back to package name for binary)
64+
echo "binary=$(echo "$METADATA" | jq -r '.packages[0].metadata.symposium.binary // .packages[0].name')" >> $GITHUB_OUTPUT
65+
66+
# Args and env as JSON (empty array/object if not specified)
67+
echo "args=$(echo "$METADATA" | jq -c '.packages[0].metadata.symposium.args // []')" >> $GITHUB_OUTPUT
68+
echo "env=$(echo "$METADATA" | jq -c '.packages[0].metadata.symposium.env // {}')" >> $GITHUB_OUTPUT
69+
70+
build:
71+
name: Build (${{ matrix.target }})
72+
needs: metadata
73+
strategy:
74+
fail-fast: false
75+
matrix:
76+
include:
77+
- target: x86_64-unknown-linux-musl
78+
os: ubuntu-latest
79+
use_musl: true
80+
- target: x86_64-unknown-linux-gnu
81+
os: ubuntu-latest
82+
use_musl: false
83+
- target: aarch64-unknown-linux-musl
84+
os: ubuntu-24.04-arm
85+
use_musl: true
86+
- target: aarch64-unknown-linux-gnu
87+
os: ubuntu-24.04-arm
88+
use_musl: false
89+
- target: x86_64-apple-darwin
90+
os: macos-13
91+
use_musl: false
92+
- target: aarch64-apple-darwin
93+
os: macos-14
94+
use_musl: false
95+
- target: x86_64-pc-windows-msvc
96+
os: windows-latest
97+
use_musl: false
98+
runs-on: ${{ matrix.os }}
99+
# Only run Linux builds that match the musl input; macOS/Windows always run
100+
if: ${{ !contains(matrix.target, 'unknown-linux') || matrix.use_musl == inputs.musl }}
101+
steps:
102+
- uses: actions/checkout@v4
103+
104+
- name: Enable long paths (Windows)
105+
if: runner.os == 'Windows'
106+
run: git config --system core.longpaths true
107+
108+
- uses: dtolnay/rust-toolchain@stable
109+
with:
110+
targets: ${{ matrix.target }}
111+
112+
- uses: Swatinem/rust-cache@v2
113+
with:
114+
key: ${{ matrix.target }}
115+
116+
- name: Install musl tools
117+
if: matrix.use_musl
118+
run: sudo apt-get update && sudo apt-get install -y musl-tools
119+
120+
- name: Build release binary
121+
run: cargo build --release --target ${{ matrix.target }} --manifest-path ${{ inputs.manifest }}
122+
123+
- name: Determine archive name
124+
id: archive
125+
shell: bash
126+
run: |
127+
# Parse target triple: arch-vendor-os[-env]
128+
TARGET="${{ matrix.target }}"
129+
ARCH=$(echo "$TARGET" | cut -d'-' -f1)
130+
OS=$(echo "$TARGET" | cut -d'-' -f3)
131+
132+
# Normalize OS names
133+
case "$OS" in
134+
apple) OS="macos" ;;
135+
pc) OS="windows" ;;
136+
unknown) OS="linux" ;;
137+
esac
138+
139+
BINARY="${{ needs.metadata.outputs.binary }}"
140+
VERSION="${{ needs.metadata.outputs.version }}"
141+
142+
if [[ "$OS" == "windows" ]]; then
143+
echo "name=${BINARY}-${OS}-${ARCH}-v${VERSION}.zip" >> $GITHUB_OUTPUT
144+
echo "ext=.exe" >> $GITHUB_OUTPUT
145+
else
146+
echo "name=${BINARY}-${OS}-${ARCH}-v${VERSION}.tar.gz" >> $GITHUB_OUTPUT
147+
echo "ext=" >> $GITHUB_OUTPUT
148+
fi
149+
150+
- name: Package (Unix)
151+
if: runner.os != 'Windows'
152+
shell: bash
153+
run: |
154+
BINARY="${{ needs.metadata.outputs.binary }}"
155+
TARGET="${{ matrix.target }}"
156+
tar -czvf "${{ steps.archive.outputs.name }}" \
157+
-C "target/${TARGET}/release" \
158+
"${BINARY}"
159+
160+
- name: Package (Windows)
161+
if: runner.os == 'Windows'
162+
shell: pwsh
163+
run: |
164+
$binary = "${{ needs.metadata.outputs.binary }}.exe"
165+
$target = "${{ matrix.target }}"
166+
Compress-Archive -Path "target\${target}\release\${binary}" -DestinationPath "${{ steps.archive.outputs.name }}"
167+
168+
- name: Upload to release
169+
uses: softprops/action-gh-release@v2
170+
with:
171+
files: ${{ steps.archive.outputs.name }}
172+
173+
extension-json:
174+
name: Generate extension.json
175+
needs: [metadata, build]
176+
runs-on: ubuntu-latest
177+
steps:
178+
- name: Generate extension.json
179+
shell: bash
180+
env:
181+
NAME: ${{ needs.metadata.outputs.name }}
182+
VERSION: ${{ needs.metadata.outputs.version }}
183+
BINARY: ${{ needs.metadata.outputs.binary }}
184+
DESCRIPTION: ${{ needs.metadata.outputs.description }}
185+
ARGS: ${{ needs.metadata.outputs.args }}
186+
ENV_VARS: ${{ needs.metadata.outputs.env }}
187+
EXTRA_ARGS: ${{ inputs.extra_args }}
188+
EXTRA_ENV: ${{ inputs.extra_env }}
189+
run: |
190+
jq -n \
191+
--arg name "$NAME" \
192+
--arg version "$VERSION" \
193+
--arg binary "$BINARY" \
194+
--arg description "$DESCRIPTION" \
195+
--argjson args "$ARGS" \
196+
--argjson env "$ENV_VARS" \
197+
--argjson extra_args "$EXTRA_ARGS" \
198+
--argjson extra_env "$EXTRA_ENV" \
199+
'{
200+
name: $name,
201+
version: $version,
202+
description: $description,
203+
binary: $binary,
204+
args: ($args + $extra_args),
205+
env: ($env * $extra_env),
206+
platforms: {
207+
"macos-arm64": "\($binary)-macos-aarch64-v\($version).tar.gz",
208+
"macos-x64": "\($binary)-macos-x86_64-v\($version).tar.gz",
209+
"linux-arm64": "\($binary)-linux-aarch64-v\($version).tar.gz",
210+
"linux-x64": "\($binary)-linux-x86_64-v\($version).tar.gz",
211+
"windows-x64": "\($binary)-windows-x86_64-v\($version).zip"
212+
}
213+
}' > extension.json
214+
cat extension.json
215+
216+
- name: Upload extension.json to release
217+
uses: softprops/action-gh-release@v2
218+
with:
219+
files: extension.json

README.md

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# package-agent-extension
2+
3+
Reusable GitHub workflow for building and releasing Symposium agent extensions.
4+
5+
Builds cross-platform binaries (macOS, Linux, Windows) and uploads them to GitHub releases with an `extension.json` manifest for the ACP registry.
6+
7+
## Usage
8+
9+
Create `.github/workflows/release.yml` in your extension repository:
10+
11+
```yaml
12+
name: Release
13+
14+
on:
15+
release:
16+
types: [published]
17+
18+
jobs:
19+
build:
20+
permissions:
21+
contents: write
22+
uses: symposium-dev/package-agent-extension/.github/workflows/build.yml@v1
23+
with:
24+
musl: true # Use musl for static Linux binaries
25+
secrets: inherit
26+
```
27+
28+
### Inputs
29+
30+
| Input | Required | Default | Description |
31+
|-------|----------|---------|-------------|
32+
| `manifest` | No | `./Cargo.toml` | Path to Cargo.toml |
33+
| `musl` | Yes | - | Use musl for Linux builds (static linking) |
34+
| `extra_args` | No | `[]` | Additional args to append (JSON array) |
35+
| `extra_env` | No | `{}` | Additional env vars to merge (JSON object) |
36+
37+
The `extra_args` and `extra_env` inputs are merged with values from `Cargo.toml`. This is useful for secrets that only live in CI:
38+
39+
```yaml
40+
jobs:
41+
build:
42+
permissions:
43+
contents: write
44+
uses: symposium-dev/package-agent-extension/.github/workflows/build.yml@v1
45+
with:
46+
musl: true
47+
extra_env: '{"API_KEY": "${{ secrets.API_KEY }}"}'
48+
```
49+
50+
### Cargo.toml Metadata
51+
52+
The workflow reads package metadata from your `Cargo.toml`. Configure runtime behavior via `[package.metadata.symposium]`:
53+
54+
```toml
55+
[package]
56+
name = "my-extension"
57+
version = "0.1.0"
58+
description = "An agent extension for X"
59+
60+
[package.metadata.symposium]
61+
binary = "my-ext" # Optional: defaults to package name
62+
args = ["--mcp", "--verbose"] # Optional: arguments passed when spawning
63+
env = { API_KEY = "default" } # Optional: environment variables
64+
```
65+
66+
All fields are optional. The generated `extension.json` includes these values so Symposium knows how to spawn the extension.
67+
68+
## Targets
69+
70+
The workflow builds for these platforms:
71+
72+
| Platform | Target | Runner |
73+
|----------|--------|--------|
74+
| macOS ARM | `aarch64-apple-darwin` | `macos-14` |
75+
| macOS x64 | `x86_64-apple-darwin` | `macos-13` |
76+
| Linux ARM | `aarch64-unknown-linux-{musl,gnu}` | `ubuntu-24.04-arm` |
77+
| Linux x64 | `x86_64-unknown-linux-{musl,gnu}` | `ubuntu-latest` |
78+
| Windows x64 | `x86_64-pc-windows-msvc` | `windows-latest` |
79+
80+
## Output
81+
82+
For each release, the workflow uploads:
83+
84+
- `{binary}-{os}-{arch}-v{version}.tar.gz` (Unix)
85+
- `{binary}-{os}-{arch}-v{version}.zip` (Windows)
86+
- `extension.json` - manifest for the ACP registry
87+
88+
## Requirements
89+
90+
Callers must set `permissions: contents: write` - the reusable workflow cannot elevate permissions.

0 commit comments

Comments
 (0)