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
64 changes: 64 additions & 0 deletions .github/workflows/compatibility.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Validate package compatibility

on:
pull_request:
paths:
- compatibility.json
- tests/**
- .github/workflows/compatibility.yml
push:
branches: [main]
paths:
- compatibility.json
- tests/**
- .github/workflows/compatibility.yml
workflow_dispatch:

permissions:
contents: read

jobs:
compatibility:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- uses: actions/setup-node@v4
with:
node-version: "22"

- name: Validate Python SDK signatures
run: |
version="$(python3 -c 'import json; print(json.load(open("compatibility.json"))["agentmail"]["python"])')"
python3 -m pip install "agentmail==$version"
python3 tests/test_sdk_signatures.py

- name: Run Python webhook verification fixtures
run: |
python3 -m pip install svix
python3 tests/test_webhook_verification.py

- name: Type-check TypeScript compatibility fixtures
run: |
sdk="$(node -p "require('./compatibility.json').agentmail.typescript")"
toolkit="$(node -p "require('./compatibility.json').toolkit.typescript")"
tmp="$(mktemp -d)"
cp tests/sdk_typescript.ts tests/webhook_typescript.ts tests/webhook_verification.ts tests/package.json "$tmp/"
cd "$tmp"
npm install --no-save "agentmail@$sdk" "agentmail-toolkit@$toolkit" "ai@6" "langchain@1" "svix" "express" "@types/express" "typescript@5.9.3" "tsx" "@types/node@22"
./node_modules/.bin/tsc --noEmit --strict --skipLibCheck --target ES2022 --module NodeNext --moduleResolution NodeNext sdk_typescript.ts webhook_typescript.ts webhook_verification.ts
./node_modules/.bin/tsx webhook_verification.ts

- name: Validate CLI command names
run: |
version="$(node -p "require('./compatibility.json').cli")"
npx -y "agentmail-cli@$version" inboxes --help | tee /tmp/inboxes-help
npx -y "agentmail-cli@$version" inboxes:messages --help | tee /tmp/messages-help
grep -q "get" /tmp/inboxes-help
grep -q "get" /tmp/messages-help
! grep -q "retrieve" /tmp/inboxes-help
! grep -q "retrieve" /tmp/messages-help
11 changes: 11 additions & 0 deletions .github/workflows/drift.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
name: Check upstream drift

on:
pull_request:
paths:
- compatibility.json
- scripts/check_compatibility.py
- .github/workflows/drift.yml
push:
branches: [main]
paths:
- compatibility.json
- scripts/check_compatibility.py
- .github/workflows/drift.yml
schedule:
- cron: "17 16 * * 1"
workflow_dispatch:
Expand Down
57 changes: 57 additions & 0 deletions .github/workflows/marketplace.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Validate marketplaces

on:
pull_request:
paths:
- .agents/**
- .claude-plugin/**
- .codex-plugin/**
- .cursor-plugin/**
- .plugin/**
- .mcp.json
- assets/**
- skills/**
- .github/workflows/marketplace.yml
push:
branches: [main]
paths:
- .agents/**
- .claude-plugin/**
- .codex-plugin/**
- .cursor-plugin/**
- .plugin/**
- .mcp.json
- assets/**
- skills/**
- .github/workflows/marketplace.yml
schedule:
- cron: "37 16 * * 1"
workflow_dispatch:

permissions:
contents: read

jobs:
marketplace:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: "22"

- name: Validate Codex marketplace installation
run: |
npm install --global @openai/codex
codex_home="$(mktemp -d)"
CODEX_HOME="$codex_home" codex plugin marketplace add . --json
CODEX_HOME="$codex_home" codex plugin list --available --json | tee /tmp/codex-plugins.json
grep -q '"pluginId": "agentmail@agentmail"' /tmp/codex-plugins.json
CODEX_HOME="$codex_home" codex plugin add agentmail@agentmail --json

- name: Validate Claude plugin
run: |
npm install --global @anthropic-ai/claude-code
claude plugin validate . --strict
claude plugin validate .claude-plugin/plugin.json --strict
47 changes: 0 additions & 47 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,52 +19,5 @@ jobs:
with:
python-version: "3.12"

- uses: actions/setup-node@v4
with:
node-version: "22"

- name: Validate repository structure
run: python3 scripts/validate_repo.py

- name: Validate Python SDK signatures
run: |
python3 -m pip install "agentmail==0.5.8"
python3 tests/test_sdk_signatures.py

- name: Run Python webhook verification fixtures
run: |
python3 -m pip install svix
python3 tests/test_webhook_verification.py

- name: Type-check and run TypeScript SDK examples
run: |
tmp="$(mktemp -d)"
cp tests/sdk_typescript.ts tests/webhook_typescript.ts tests/webhook_verification.ts tests/package.json "$tmp/"
cd "$tmp"
npm install --no-save "agentmail@0.5.17" "agentmail-toolkit@0.5.1" "ai@6" "langchain@1" "svix" "express" "@types/express" "typescript@5.9.3" "tsx" "@types/node@22"
./node_modules/.bin/tsc --noEmit --strict --skipLibCheck --target ES2022 --module NodeNext --moduleResolution NodeNext sdk_typescript.ts webhook_typescript.ts webhook_verification.ts
./node_modules/.bin/tsx webhook_verification.ts

- name: Validate CLI command names
run: |
npx -y agentmail-cli@0.7.14 inboxes --help | tee /tmp/inboxes-help
npx -y agentmail-cli@0.7.14 inboxes:messages --help | tee /tmp/messages-help
grep -q "get" /tmp/inboxes-help
grep -q "get" /tmp/messages-help
! grep -q "retrieve" /tmp/inboxes-help
! grep -q "retrieve" /tmp/messages-help

- name: Validate Codex marketplace installation
run: |
npm install --global @openai/codex
codex_home="$(mktemp -d)"
CODEX_HOME="$codex_home" codex plugin marketplace add . --json
CODEX_HOME="$codex_home" codex plugin list --available --json | tee /tmp/codex-plugins.json
grep -q '"pluginId": "agentmail@agentmail"' /tmp/codex-plugins.json
CODEX_HOME="$codex_home" codex plugin add agentmail@agentmail --json

- name: Validate Claude plugin
run: |
npm install --global @anthropic-ai/claude-code
claude plugin validate . --strict
claude plugin validate .claude-plugin/plugin.json --strict
8 changes: 0 additions & 8 deletions compatibility.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,5 @@
"toolkit": {
"typescript": "0.5.1",
"python": "0.3.0"
},
"hostedMcp": {
"url": "https://mcp.agentmail.to/mcp",
"source": "https://github.com/agentmail-to/agentmail-mcp"
},
"specifications": {
"openapi": "https://docs.agentmail.to/openapi.json",
"asyncapi": "https://docs.agentmail.to/asyncapi.json"
}
}
21 changes: 2 additions & 19 deletions scripts/check_compatibility.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
#!/usr/bin/env python3
"""Fail when verified AgentMail dependencies or public specs have drifted."""
"""Fail when verified AgentMail package versions have drifted."""

from __future__ import annotations

import json
import sys
import urllib.error
import urllib.request
from pathlib import Path

Expand Down Expand Up @@ -42,22 +41,6 @@ def fetch_json(url: str) -> dict:
if version != expected[name]
]

openapi = fetch_json(EXPECTED["specifications"]["openapi"])
asyncapi = fetch_json(EXPECTED["specifications"]["asyncapi"])
if not str(openapi.get("openapi", "")).startswith("3."):
errors.append("AgentMail OpenAPI document is missing an OpenAPI 3.x marker")
if not str(asyncapi.get("asyncapi", "")).startswith("2."):
errors.append("AgentMail AsyncAPI document is missing an AsyncAPI 2.x marker")

try:
request = urllib.request.Request(EXPECTED["hostedMcp"]["url"], headers=HEADERS)
urllib.request.urlopen(request, timeout=20).close()
except urllib.error.HTTPError as exc:
if exc.code not in {401, 405}:
errors.append(f"hosted MCP probe returned unexpected HTTP {exc.code}")
except urllib.error.URLError as exc:
errors.append(f"hosted MCP probe failed: {exc}")

if errors:
print("Compatibility drift detected:", file=sys.stderr)
for item in errors:
Expand All @@ -66,4 +49,4 @@ def fetch_json(url: str) -> dict:

for name in sorted(actual):
print(f"{name}: {actual[name]}")
print("AgentMail OpenAPI, AsyncAPI, and hosted MCP probes passed")
print("AgentMail package versions match compatibility.json")
Loading