diff --git a/.enforcer-scripts/validate-jbang-versions.groovy b/.enforcer-scripts/validate-jbang-versions.groovy
new file mode 100644
index 000000000..b8f283319
--- /dev/null
+++ b/.enforcer-scripts/validate-jbang-versions.groovy
@@ -0,0 +1,37 @@
+// Fetch the property from the Maven project
+def scriptName = project.properties['jbang.script.name']
+
+// Fail if the script property is missing
+if (scriptName == null) {
+ throw new IllegalStateException("[ERROR] JBang validator: No jbang.script.name set in properties")
+}
+
+def jbangFile = new File(project.basedir, scriptName)
+if (!jbangFile.exists()) {
+ // If a script name was explicitly provided but doesn't exist, fail.
+ // If using the fallback, we might want to just skip (return true).
+ throw new IllegalStateException("[ERROR] JBang validator: File not found: " + jbangFile.absolutePath)
+}
+
+def expectedVersion = project.version
+def groupPrefix = "//DEPS io.github.a2asdk:"
+def success = true
+
+jbangFile.eachLine { line ->
+ if (line.trim().startsWith(groupPrefix)) {
+ def lastColon = line.lastIndexOf(":")
+ if (lastColon != -1) {
+ def actualVersion = line.substring(lastColon + 1).trim().tokenize()[0]
+ if (actualVersion != expectedVersion) {
+ System.err.println("[ERROR] JBang Version Mismatch in " + scriptName)
+ System.err.println(" Expected: " + expectedVersion)
+ System.err.println(" Found: " + actualVersion + " in line: \"" + line.trim() + "\"")
+ success = false
+ }
+ }
+ }
+}
+
+if (!success) {
+ throw new IllegalStateException("[ERROR] JBang version validation failed")
+}
\ No newline at end of file
diff --git a/.github/workflows/create-github-release.yml b/.github/workflows/create-github-release.yml
new file mode 100644
index 000000000..15baee6c5
--- /dev/null
+++ b/.github/workflows/create-github-release.yml
@@ -0,0 +1,127 @@
+name: Create GitHub Release
+
+on:
+ push:
+ tags:
+ - 'v?[0-9]+.[0-9]+.[0-9]+*' # Trigger on tags like v1.0.0, 1.2.3, v1.2.3.Alpha1 etc.
+
+jobs:
+ create-release:
+ # Only run this job for the main repository, not for forks
+ if: github.repository == 'a2aproject/a2a-java'
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write # Required to create releases
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # Fetch all history for changelog generation
+
+ - name: Extract version from tag
+ id: version
+ run: |
+ # Remove 'v' prefix if present
+ VERSION=${GITHUB_REF_NAME#v}
+ echo "version=$VERSION" >> $GITHUB_OUTPUT
+ echo "Version: $VERSION"
+
+ - name: Generate release notes
+ id: release_notes
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const version = '${{ steps.version.outputs.version }}';
+
+ // Get the previous tag
+ let previousTag = '';
+ try {
+ const { data: tags } = await github.rest.repos.listTags({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ per_page: 100
+ });
+
+ // Find current tag index
+ const currentIndex = tags.findIndex(tag => tag.name === context.ref.replace('refs/tags/', ''));
+
+ // Get previous tag (next in list)
+ if (currentIndex >= 0 && currentIndex < tags.length - 1) {
+ previousTag = tags[currentIndex + 1].name;
+ }
+ } catch (error) {
+ console.log('Could not fetch previous tag:', error.message);
+ }
+
+ // Build release notes
+ let releaseNotes = `## A2A Java SDK ${version}\n\n`;
+
+ // Add Maven Central installation instructions
+ releaseNotes += `### Installation\n\n`;
+ releaseNotes += `**Maven**:\n\`\`\`xml\n\n`;
+ releaseNotes += ` io.github.a2asdk\n`;
+ releaseNotes += ` a2a-java-sdk-client\n`;
+ releaseNotes += ` ${version}\n`;
+ releaseNotes += `\n\`\`\`\n\n`;
+
+ releaseNotes += `**Gradle**:\n\`\`\`gradle\n`;
+ releaseNotes += `implementation 'io.github.a2asdk:a2a-java-sdk-client:${version}'\n`;
+ releaseNotes += `\`\`\`\n\n`;
+
+ // Add links
+ releaseNotes += `### Links\n\n`;
+ releaseNotes += `- [Maven Central](https://central.sonatype.com/artifact/io.github.a2asdk/a2a-java-sdk-parent/${version})\n`;
+ releaseNotes += `- [JavaDoc](https://javadoc.io/doc/io.github.a2asdk/a2a-java-sdk-parent/${version})\n`;
+ releaseNotes += `- [GitHub](https://github.com/a2aproject/a2a-java/tree/v${version})\n\n`;
+
+ // Add changelog header
+ if (previousTag) {
+ releaseNotes += `### Changes since ${previousTag}\n\n`;
+ releaseNotes += `[Full Changelog](https://github.com/a2aproject/a2a-java/compare/${previousTag}...v${version})\n\n`;
+ } else {
+ releaseNotes += `### Changes\n\n`;
+ }
+
+ return releaseNotes;
+
+ - name: Create GitHub Release
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const version = '${{ steps.version.outputs.version }}';
+ const tag = context.ref.replace('refs/tags/', '');
+ const releaseNotes = ${{ steps.release_notes.outputs.result }};
+
+ // Determine if this is a pre-release
+ const isPrerelease = version.includes('Alpha') ||
+ version.includes('Beta') ||
+ version.includes('RC') ||
+ version.includes('SNAPSHOT');
+
+ try {
+ const { data: release } = await github.rest.repos.createRelease({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ tag_name: tag,
+ name: `v${version}`,
+ body: releaseNotes,
+ draft: false,
+ prerelease: isPrerelease,
+ generate_release_notes: true // GitHub will append auto-generated notes
+ });
+
+ console.log(`✅ Created release: ${release.html_url}`);
+ core.summary
+ .addHeading(`Release v${version} Created`)
+ .addLink('View Release', release.html_url)
+ .addLink('Maven Central', `https://central.sonatype.com/artifact/io.github.a2asdk/a2a-java-sdk-parent/${version}`)
+ .write();
+
+ } catch (error) {
+ if (error.status === 422 && error.message.includes('already_exists')) {
+ console.log('⚠️ Release already exists for this tag');
+ } else {
+ throw error;
+ }
+ }
diff --git a/RELEASE.md b/RELEASE.md
new file mode 100644
index 000000000..079a18e94
--- /dev/null
+++ b/RELEASE.md
@@ -0,0 +1,274 @@
+# Release Process
+
+This document describes the process for releasing a new version of the A2A Java SDK to Maven Central.
+
+## Overview
+
+The release process involves:
+1. Updating version numbers across the project (automated)
+2. Opening and merging a release PR
+3. Tagging the release
+4. Automatic deployment to Maven Central
+5. Automatic GitHub release creation
+6. Incrementing to next SNAPSHOT version
+
+## Prerequisites
+
+### Required Accounts & Access
+- GitHub repository write access to `a2aproject/a2a-java`
+- Maven Central account: namespace: `io.github.a2asdk`
+
+### Required Secrets (Repository Maintainers)
+The following secrets must be configured in GitHub repository settings:
+- `GPG_SIGNING_KEY`: Private GPG key for artifact signing
+- `GPG_SIGNING_PASSPHRASE`: Passphrase for the GPG key
+- `CENTRAL_TOKEN_USERNAME`: Maven Central username token
+- `CENTRAL_TOKEN_PASSWORD`: Maven Central password token
+
+## Release Steps
+
+The examples below use versions like `0.4.0.Alpha1-SNAPSHOT` and `0.4.0.Alpha1` for demonstration. Be sure to substitute these with the actual versions for your release.
+
+### 1. Prepare Release Version
+
+Use the provided script to update all version numbers:
+
+```bash
+# Preview changes (dry run)
+./update-version.sh 0.4.0.Alpha1-SNAPSHOT 0.4.0.Alpha1 --dry-run
+
+# Apply version update
+./update-version.sh 0.4.0.Alpha1-SNAPSHOT 0.4.0.Alpha1
+```
+
+The script automatically updates:
+- ✅ All `pom.xml` files
+- ✅ All JBang script `//DEPS` declarations in `examples/`
+- ✅ Validates the JBang update with built-in GMavenPlus validation
+
+**What gets updated**:
+```
+pom.xml: 0.4.0.Alpha1-SNAPSHOT → 0.4.0.Alpha1
+//DEPS io.github...: 0.4.0.Alpha1-SNAPSHOT → 0.4.0.Alpha1
+```
+
+### 2. Verify Changes
+
+Review the changes before committing:
+
+```bash
+# Review all changes
+git diff
+
+# Verify build works
+mvn clean install
+```
+
+### 3. Create Release PR
+
+Create a pull request with the version update:
+
+```bash
+git checkout -b release/0.4.0.Alpha1
+git add -A
+git commit -m "chore: release 0.4.0.Alpha1"
+git push origin release/0.4.0.Alpha1
+```
+
+Open PR on GitHub with title: `chore: release 0.4.0.Alpha1`
+
+### 4. CI Verification
+
+The `build-with-release-profile.yml` workflow automatically verifies:
+- ✅ Build succeeds with `-Prelease` profile
+- ✅ All JavaDoc generation succeeds
+- ✅ GPG signing works correctly
+- ✅ JBang version validation passes
+- ✅ No compilation or test failures
+
+**Important**: This workflow tests the actual PR branch (not main) to catch issues before merge.
+
+Wait for all CI checks to pass before proceeding.
+
+### 5. Merge Release PR
+
+Once all checks pass and the PR is approved:
+- Merge the PR to `main` branch
+- **Do NOT squash** - keep the release commit message intact for changelog
+
+### 6. Tag and Push
+
+After the PR is merged to main:
+
+```bash
+# Switch to main and pull the merged changes
+git checkout main
+git pull origin main
+
+# Create annotated tag
+git tag -a v0.4.0.Alpha1 -m "Release 0.4.0.Alpha1"
+
+# Push the tag (triggers deployment + GitHub release)
+git push origin v0.4.0.Alpha1
+```
+
+### 7. Automated Workflows Triggered
+
+Pushing the tag triggers **two workflows**:
+
+#### A. Maven Central Deployment (`release-to-maven-central.yml`)
+1. Detects tag (pattern: `v?[0-9]+.[0-9]+.[0-9]+*`)
+2. Checks out the tagged commit
+3. Builds with `-Prelease -DskipTests`
+4. Signs all artifacts with GPG
+5. Deploys to Maven Central with auto-publish
+
+**⏱️ Deployment typically takes 30 minutes**, but can vary.
+
+#### B. GitHub Release Creation (`create-github-release.yml`)
+1. Detects the same tag
+2. Extracts version from tag name
+3. Generates release notes from commits since last release
+4. Creates GitHub release with:
+ - Auto-generated changelog
+ - Link to Maven Central artifacts
+ - Installation instructions
+
+### 8. Verify Deployment
+
+Check that artifacts are available:
+
+**Maven Central**:
+```
+https://central.sonatype.com/artifact/io.github.a2asdk/a2a-java-sdk-parent/0.4.0.Alpha1
+```
+
+**GitHub Release**:
+```
+https://github.com/a2aproject/a2a-java/releases/tag/v0.4.0.Alpha1
+```
+
+Artifacts should include:
+- `.jar` files (main artifacts)
+- `-sources.jar` (source code)
+- `-javadoc.jar` (JavaDoc)
+- `.pom` files
+- `.asc` GPG signatures for all artifacts
+
+### 9. Increment to Next SNAPSHOT
+
+Prepare repository for next development cycle:
+
+```bash
+# Update to next SNAPSHOT version
+./update-version.sh 0.4.0.Alpha1 0.4.0.Alpha2-SNAPSHOT
+
+# Create and push PR
+git checkout -b chore/bump-to-0.4.0.Alpha2-SNAPSHOT
+git add -A
+git commit -m "chore: bump version to 0.4.0.Alpha2-SNAPSHOT"
+git push origin chore/bump-to-0.4.0.Alpha2-SNAPSHOT
+```
+
+Open PR, wait for CI, and merge.
+
+## Troubleshooting
+
+### Build fails with "JBang version mismatch"
+
+**Cause**: JBang script dependencies don't match POM version
+
+**Fix**:
+```bash
+# Re-run the update script to fix mismatches
+./update-version.sh OLD_VERSION NEW_VERSION
+
+# Or manually check:
+grep -r "//DEPS io.github.a2asdk:" examples/
+```
+
+### GPG signing fails in workflow
+
+**Cause**: GPG secrets are missing or incorrect
+
+**Fix**: Repository maintainers - verify secrets in:
+```
+Settings → Secrets and variables → Actions
+```
+Check: `GPG_SIGNING_KEY`, `GPG_SIGNING_PASSPHRASE`
+
+### Maven Central deployment times out
+
+**Cause**: Normal Maven Central processing delays
+
+**Fix**: Wait (up to 2 hours). Check status:
+```
+https://central.sonatype.com/publishing
+```
+
+### Deployment fails with authentication error
+
+**Cause**: Maven Central tokens expired or incorrect
+
+**Fix**: Repository maintainers:
+1. Log in to Maven Central with the GitHub account for the a2asdk user.
+2. Generate new tokens: `User → Generate User Token`
+3. Update secrets: `CENTRAL_TOKEN_USERNAME` and `CENTRAL_TOKEN_PASSWORD`
+
+### GitHub release not created
+
+**Cause**: Workflow failed or tag pattern didn't match
+
+**Fix**:
+```bash
+# Check workflow runs
+https://github.com/a2aproject/a2a-java/actions
+
+# Manually create release if needed
+https://github.com/a2aproject/a2a-java/releases/new
+```
+
+### Need to rollback a release
+
+**Not possible** - Maven Central does not allow artifact deletion.
+
+**Mitigation**:
+1. Release a patch version with fixes (e.g., `0.4.0.Alpha1` → `0.4.0.Alpha2`)
+2. Document issues in GitHub release notes
+3. Update documentation to recommend correct version
+
+## Version Numbering
+
+Follow semantic versioning with qualifiers:
+
+- **Major.Minor.Patch** - Standard releases (e.g., `1.0.0`)
+- **Major.Minor.Patch.AlphaN** - Alpha releases (e.g., `0.4.0.Alpha1`)
+- **Major.Minor.Patch.BetaN** - Beta releases (e.g., `0.3.0.Beta1`)
+- **Major.Minor.Patch.RCN** - Release candidates (e.g., `1.0.0.RC1`)
+- **-SNAPSHOT** - Development versions (e.g., `0.4.0.Alpha2-SNAPSHOT`)
+
+## Workflows Reference
+
+### build-with-release-profile.yml
+- **Triggers**: All PRs, all pushes
+- **Purpose**: Verify builds with `-Prelease` profile
+- **Special**: Tests actual PR branch (not main) using `pull_request_target` with explicit checkout
+- **Requires**: GPG and Maven Central secrets
+
+### release-to-maven-central.yml
+- **Triggers**: Tags matching `v?[0-9]+.[0-9]+.[0-9]+*`
+- **Purpose**: Deploy to Maven Central
+- **Duration**: ~30 minutes
+- **Requires**: GPG and Maven Central secrets
+
+### create-github-release.yml
+- **Triggers**: Tags matching `v?[0-9]+.[0-9]+.[0-9]+*`
+- **Purpose**: Create GitHub release with changelog
+- **Features**: Auto-generated release notes, Maven Central links
+- **Requires**: Default `GITHUB_TOKEN` (automatic)
+
+## Support
+
+For questions or issues with the release process:
+- Open an issue: https://github.com/a2aproject/a2a-java/issues
+- Reference: [Issue #532](https://github.com/a2aproject/a2a-java/issues/532) - Release process improvements
diff --git a/examples/helloworld/client/pom.xml b/examples/helloworld/client/pom.xml
index 2e8a3f3f0..c362ce9a9 100644
--- a/examples/helloworld/client/pom.xml
+++ b/examples/helloworld/client/pom.xml
@@ -15,6 +15,10 @@
Java SDK A2A Examples
Examples for the Java SDK for the Agent2Agent Protocol (A2A)
+
+ src/main/java/io/a2a/examples/helloworld/HelloWorldRunner.java
+
+
io.github.a2asdk
@@ -39,6 +43,24 @@
org.apache.maven.plugins
maven-surefire-plugin
+
+ org.codehaus.gmavenplus
+ gmavenplus-plugin
+
+
+ validate-jbang-versions
+ validate
+
+ execute
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 8242e9462..c7987fd54 100644
--- a/pom.xml
+++ b/pom.xml
@@ -42,12 +42,15 @@
UTF-8
3.5.0
3.14.1
+ 3.6.2
3.4.2
3.3.1
3.1.2
3.8.0
3.2.4
+ 4.2.1
0.8.0
+ 5.0.3
2.13.2
4.1.0
2.0.1
@@ -388,6 +391,25 @@
+
+ org.codehaus.gmavenplus
+ gmavenplus-plugin
+ ${gmavenplus-plugin.version}
+
+
+ org.apache.groovy
+ groovy
+ ${groovy.version}
+ runtime
+
+
+ org.apache.groovy
+ groovy-ant
+ ${groovy.version}
+ runtime
+
+
+
org.apache.maven.plugins
maven-jar-plugin
diff --git a/update-version.sh b/update-version.sh
new file mode 100755
index 000000000..98a6cb3cd
--- /dev/null
+++ b/update-version.sh
@@ -0,0 +1,132 @@
+#!/bin/bash
+
+# Update version across POMs and JBang scripts
+# Usage: ./update-version.sh FROM_VERSION TO_VERSION [--dry-run]
+
+set -euo pipefail # Exit on error, unset var, and pipe failure
+
+FROM_VERSION=$1
+TO_VERSION=$2
+
+# Validate arguments
+if [ -z "$FROM_VERSION" ] || [ -z "$TO_VERSION" ]; then
+ echo "❌ Error: Missing version arguments."
+ echo "Usage: $0 FROM_VERSION TO_VERSION [--dry-run]"
+ echo "Example: $0 0.3.0.Beta1-SNAPSHOT 0.3.0.Beta1"
+ exit 1
+fi
+
+# Check if TO_VERSION looks like a flag
+if [[ "$TO_VERSION" == --* ]]; then
+ echo "❌ Error: TO_VERSION cannot be a flag. Did you mean to provide both FROM_VERSION and TO_VERSION?"
+ echo "Usage: $0 FROM_VERSION TO_VERSION [--dry-run]"
+ echo "Example: $0 0.3.0.Beta1-SNAPSHOT 0.3.0.Beta1"
+ exit 1
+fi
+
+DRY_RUN=false
+if [ "$3" = "--dry-run" ]; then
+ DRY_RUN=true
+elif [ -n "$3" ]; then
+ echo "❌ Error: Invalid third argument. Only '--dry-run' is supported."
+ echo "Usage: $0 FROM_VERSION TO_VERSION [--dry-run]"
+ exit 1
+fi
+
+# Verify we're in the right directory
+if [ ! -f "pom.xml" ]; then
+ echo "❌ Error: pom.xml not found. Run this script from the a2a-java root directory."
+ exit 1
+fi
+
+echo "🔍 Updating version from $FROM_VERSION → $TO_VERSION"
+echo ""
+
+# Find all files to update
+POM_FILES=$(find . -type f -name "pom.xml" | sort)
+JBANG_FILES=$(find . -type f -name "*.java" -path "*/examples/*" -exec grep -l "//DEPS io.github.a2asdk:" {} \; | sort)
+
+POM_COUNT=$(echo "$POM_FILES" | wc -l | tr -d ' ')
+JBANG_COUNT=$(echo "$JBANG_FILES" | wc -l | tr -d ' ')
+
+echo "📄 Found $POM_COUNT pom.xml files"
+echo "📄 Found $JBANG_COUNT JBang script files"
+echo ""
+
+# Show what will be changed
+if [ "$DRY_RUN" = true ]; then
+ echo "🔎 DRY RUN - showing what would be changed:"
+ echo ""
+
+ echo "=== POM files with version $FROM_VERSION ==="
+ for file in $POM_FILES; do
+ if grep -q "$FROM_VERSION" "$file"; then
+ echo " 📝 $file"
+ grep -n "$FROM_VERSION" "$file" | sed 's/^/ /'
+ fi
+ done
+ echo ""
+
+ echo "=== JBang files with version $FROM_VERSION ==="
+ for file in $JBANG_FILES; do
+ if grep -q "//DEPS io.github.a2asdk:.*:$FROM_VERSION" "$file"; then
+ echo " 📝 $file"
+ grep -n "//DEPS io.github.a2asdk:.*:$FROM_VERSION" "$file" | sed 's/^/ /'
+ fi
+ done
+ echo ""
+
+ echo "✅ Dry run complete. Run without --dry-run to apply changes."
+ exit 0
+fi
+
+# Perform actual updates
+echo "🔄 Updating files..."
+echo ""
+
+UPDATED_POMS=0
+UPDATED_JBANGS=0
+
+# Update POM files
+echo "Updating pom.xml files..."
+for file in $POM_FILES; do
+ if grep -q "$FROM_VERSION" "$file"; then
+ if [[ "$OSTYPE" == "darwin"* ]]; then
+ # macOS requires empty string after -i
+ sed -i "" -e "s|>$FROM_VERSION<|>$TO_VERSION<|g" "$file"
+ else
+ # Linux doesn't need it
+ sed -i "s|>$FROM_VERSION<|>$TO_VERSION<|g" "$file"
+ fi
+ echo " ✅ $file"
+ UPDATED_POMS=$((UPDATED_POMS + 1))
+ fi
+done
+echo ""
+
+# Update JBang files
+echo "Updating JBang script files..."
+for file in $JBANG_FILES; do
+ if grep -q "//DEPS io.github.a2asdk:.*:$FROM_VERSION" "$file"; then
+ if [[ "$OSTYPE" == "darwin"* ]]; then
+ # macOS requires empty string after -i
+ sed -i "" -e "s/\(\/\/DEPS io.github.a2asdk:.*:\)$FROM_VERSION/\1$TO_VERSION/g" "$file"
+ else
+ # Linux doesn't need it
+ sed -i "s/\(\/\/DEPS io.github.a2asdk:.*:\)$FROM_VERSION/\1$TO_VERSION/g" "$file"
+ fi
+ echo " ✅ $file"
+ UPDATED_JBANGS=$((UPDATED_JBANGS + 1))
+ fi
+done
+echo ""
+
+# Summary
+echo "✅ Version update complete!"
+echo " Updated $UPDATED_POMS pom.xml files"
+echo " Updated $UPDATED_JBANGS JBang script files"
+echo ""
+echo "📋 Next steps:"
+echo " 1. Review changes: git diff"
+echo " 2. Verify build: mvn clean install"
+echo " 3. Commit changes: git commit -am 'chore: release $TO_VERSION'"