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
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"url": "https://sent.dm"
},
"metadata": {
"description": "Official Sent skills and remote MCP integration.",
"description": "Official Sent skills and remote MCP integration for messaging operations and specialist channel workflows.",
"version": "0.1.0"
},
"plugins": [
Expand Down
17 changes: 17 additions & 0 deletions adapter-sources/shared/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"display_name": "Sent",
"short_description": "Business messaging workflows",
"long_description": "Use Sent MCP operations for safe account, contact, template, analytics, and messaging workflows. Focused specialist skills add delivery diagnosis, Sender Profile architecture, US A2P 10DLC registration, WhatsApp Business onboarding and template authoring, RCS agent launch readiness, and cross-channel template-builder design.",
"developer_name": "Sent",
"category": "Productivity",
"capabilities": ["Interactive", "Write"],
"website_url": "https://github.com/sentdm/sent-plugin#readme",
"privacy_policy_url": "https://www.sent.dm/en/legal/privacy-policy",
"terms_of_service_url": "https://www.sent.dm/en/legal/terms-of-service",
"default_prompts": [
"Use $sent-account-readiness to check whether my Sent account is messaging-ready.",
"Use $messaging-performance-analyzer to diagnose this delivery report by channel.",
"Use $sms-10dlc-registration to review my US A2P registration evidence."
],
"marketplace_description": "Official Sent skills and remote MCP integration for messaging operations and specialist channel workflows."
}
2 changes: 1 addition & 1 deletion claude-plugins/sent/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"name": "Sent",
"url": "https://sent.dm"
},
"homepage": "https://docs.sent.dm/start/llm-docs/mcp-server",
"homepage": "https://github.com/sentdm/sent-plugin#readme",
"repository": "https://github.com/sentdm/sent-plugin",
"license": "MIT",
"keywords": [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent Performance Analyzer"
short_description: "Diagnose channel delivery and engagement"
default_prompt: "Use $messaging-performance-analyzer to analyze this MDR export by channel and outcome."
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent RCS Onboarding"
short_description: "Review RCS agent launch readiness"
default_prompt: "Use $rcs-agent-onboarding to review my RCS agent readiness and missing evidence."
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent Profile Architect"
short_description: "Design safe Sender Profile boundaries"
default_prompt: "Use $sender-profile-architect to design Sender Profile boundaries for this messaging system."
4 changes: 4 additions & 0 deletions claude-plugins/sent/skills/sent/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent Workflow Router"
short_description: "Route broad Sent messaging requests"
default_prompt: "Use $sent to identify the safest Sent workflow for my request."
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent 10DLC Registration"
short_description: "Review US A2P registration evidence"
default_prompt: "Use $sms-10dlc-registration to review my 10DLC evidence packet for gaps."
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent Template Builder UI"
short_description: "Audit cross-channel template builder UX"
default_prompt: "Use $template-builder-ui to audit this template builder flow and payload mapping."
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent WABA Signup"
short_description: "Plan WhatsApp Business onboarding"
default_prompt: "Use $waba-embedded-signup to review my WABA onboarding flow and readiness."
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent WABA Template Author"
short_description: "Draft compliant WhatsApp templates"
default_prompt: "Use $waba-template-author to draft and validate a WhatsApp template payload."
2 changes: 1 addition & 1 deletion packages/sent/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"name": "Sent",
"url": "https://sent.dm"
},
"homepage": "https://docs.sent.dm/start/llm-docs/mcp-server",
"homepage": "https://github.com/sentdm/sent-plugin#readme",
"repository": "https://github.com/sentdm/sent-plugin",
"license": "MIT",
"keywords": [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent Performance Analyzer"
short_description: "Diagnose channel delivery and engagement"
default_prompt: "Use $messaging-performance-analyzer to analyze this MDR export by channel and outcome."
4 changes: 4 additions & 0 deletions packages/sent/skills/rcs-agent-onboarding/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent RCS Onboarding"
short_description: "Review RCS agent launch readiness"
default_prompt: "Use $rcs-agent-onboarding to review my RCS agent readiness and missing evidence."
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent Profile Architect"
short_description: "Design safe Sender Profile boundaries"
default_prompt: "Use $sender-profile-architect to design Sender Profile boundaries for this messaging system."
4 changes: 4 additions & 0 deletions packages/sent/skills/sent/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent Workflow Router"
short_description: "Route broad Sent messaging requests"
default_prompt: "Use $sent to identify the safest Sent workflow for my request."
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent 10DLC Registration"
short_description: "Review US A2P registration evidence"
default_prompt: "Use $sms-10dlc-registration to review my 10DLC evidence packet for gaps."
4 changes: 4 additions & 0 deletions packages/sent/skills/template-builder-ui/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent Template Builder UI"
short_description: "Audit cross-channel template builder UX"
default_prompt: "Use $template-builder-ui to audit this template builder flow and payload mapping."
4 changes: 4 additions & 0 deletions packages/sent/skills/waba-embedded-signup/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent WABA Signup"
short_description: "Plan WhatsApp Business onboarding"
default_prompt: "Use $waba-embedded-signup to review my WABA onboarding flow and readiness."
4 changes: 4 additions & 0 deletions packages/sent/skills/waba-template-author/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent WABA Template Author"
short_description: "Draft compliant WhatsApp templates"
default_prompt: "Use $waba-template-author to draft and validate a WhatsApp template payload."
2 changes: 1 addition & 1 deletion plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"name": "Sent",
"url": "https://sent.dm"
},
"homepage": "https://docs.sent.dm/start/llm-docs/mcp-server",
"homepage": "https://github.com/sentdm/sent-plugin#readme",
"repository": "https://github.com/sentdm/sent-plugin",
"license": "MIT",
"keywords": [
Expand Down
12 changes: 6 additions & 6 deletions plugins/sent/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"name": "Sent",
"url": "https://sent.dm"
},
"homepage": "https://docs.sent.dm/start/llm-docs/mcp-server",
"homepage": "https://github.com/sentdm/sent-plugin#readme",
"repository": "https://github.com/sentdm/sent-plugin",
"license": "MIT",
"keywords": [
Expand Down Expand Up @@ -34,22 +34,22 @@
"interface": {
"displayName": "Sent",
"shortDescription": "Business messaging workflows",
"longDescription": "Use Sent skills and its remote MCP server for safe messaging, contacts, templates, analytics, account readiness, SMS, WhatsApp, and RCS workflows.",
"longDescription": "Use Sent MCP operations for safe account, contact, template, analytics, and messaging workflows. Focused specialist skills add delivery diagnosis, Sender Profile architecture, US A2P 10DLC registration, WhatsApp Business onboarding and template authoring, RCS agent launch readiness, and cross-channel template-builder design.",
"developerName": "Sent",
"category": "Productivity",
"capabilities": [
"Interactive",
"Write"
],
"websiteURL": "https://www.sent.dm",
"websiteURL": "https://github.com/sentdm/sent-plugin#readme",
"privacyPolicyURL": "https://www.sent.dm/en/legal/privacy-policy",
"termsOfServiceURL": "https://www.sent.dm/en/legal/terms-of-service",
"logo": "./assets/logo.svg",
"composerIcon": "./assets/logo.svg",
"defaultPrompt": [
"Check whether my account is ready to send and flag anything blocking me.",
"Summarize message volume and deliverability for the last 30 days.",
"Find an approved template, preview an SMS to a contact, and ask before sending."
"Use $sent-account-readiness to check whether my Sent account is messaging-ready.",
"Use $messaging-performance-analyzer to diagnose this delivery report by channel.",
"Use $sms-10dlc-registration to review my US A2P registration evidence."
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent Performance Analyzer"
short_description: "Diagnose channel delivery and engagement"
default_prompt: "Use $messaging-performance-analyzer to analyze this MDR export by channel and outcome."
4 changes: 4 additions & 0 deletions plugins/sent/skills/rcs-agent-onboarding/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent RCS Onboarding"
short_description: "Review RCS agent launch readiness"
default_prompt: "Use $rcs-agent-onboarding to review my RCS agent readiness and missing evidence."
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent Profile Architect"
short_description: "Design safe Sender Profile boundaries"
default_prompt: "Use $sender-profile-architect to design Sender Profile boundaries for this messaging system."
4 changes: 4 additions & 0 deletions plugins/sent/skills/sent/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent Workflow Router"
short_description: "Route broad Sent messaging requests"
default_prompt: "Use $sent to identify the safest Sent workflow for my request."
4 changes: 4 additions & 0 deletions plugins/sent/skills/sms-10dlc-registration/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent 10DLC Registration"
short_description: "Review US A2P registration evidence"
default_prompt: "Use $sms-10dlc-registration to review my 10DLC evidence packet for gaps."
4 changes: 4 additions & 0 deletions plugins/sent/skills/template-builder-ui/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent Template Builder UI"
short_description: "Audit cross-channel template builder UX"
default_prompt: "Use $template-builder-ui to audit this template builder flow and payload mapping."
4 changes: 4 additions & 0 deletions plugins/sent/skills/waba-embedded-signup/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent WABA Signup"
short_description: "Plan WhatsApp Business onboarding"
default_prompt: "Use $waba-embedded-signup to review my WABA onboarding flow and readiness."
4 changes: 4 additions & 0 deletions plugins/sent/skills/waba-template-author/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Sent WABA Template Author"
short_description: "Draft compliant WhatsApp templates"
default_prompt: "Use $waba-template-author to draft and validate a WhatsApp template payload."
29 changes: 13 additions & 16 deletions scripts/generate_adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ def build(output_root: Path, source_root: Path = ROOT) -> None:
package = source_root / "packages" / "sent"
commands = source_root / "adapter-sources" / "claude" / "commands"
adapter_readme = source_root / "adapter-sources" / "shared" / "README.md"
marketplace = read_json(source_root / "adapter-sources" / "shared" / "marketplace.json")
metadata = load_repository_metadata(source_root)
portable_manifest = read_json(package / "plugin.json")
portable_mcp = read_json(package / "mcp.json")
Expand Down Expand Up @@ -112,22 +113,18 @@ def build(output_root: Path, source_root: Path = ROOT) -> None:
"skills": "./skills/",
"mcpServers": "./.mcp.json",
"interface": {
"displayName": "Sent",
"shortDescription": "Business messaging workflows",
"longDescription": "Use Sent skills and its remote MCP server for safe messaging, contacts, templates, analytics, account readiness, SMS, WhatsApp, and RCS workflows.",
"developerName": "Sent",
"category": "Productivity",
"capabilities": ["Interactive", "Write"],
"websiteURL": "https://www.sent.dm",
"privacyPolicyURL": "https://www.sent.dm/en/legal/privacy-policy",
"termsOfServiceURL": "https://www.sent.dm/en/legal/terms-of-service",
"displayName": marketplace["display_name"],
"shortDescription": marketplace["short_description"],
"longDescription": marketplace["long_description"],
"developerName": marketplace["developer_name"],
"category": marketplace["category"],
"capabilities": marketplace["capabilities"],
"websiteURL": marketplace["website_url"],
"privacyPolicyURL": marketplace["privacy_policy_url"],
"termsOfServiceURL": marketplace["terms_of_service_url"],
"logo": "./assets/logo.svg",
"composerIcon": "./assets/logo.svg",
"defaultPrompt": [
"Check whether my account is ready to send and flag anything blocking me.",
"Summarize message volume and deliverability for the last 30 days.",
"Find an approved template, preview an SMS to a contact, and ask before sending."
],
"defaultPrompt": marketplace["default_prompts"],
},
}
adapter_mcp = {
Expand All @@ -154,7 +151,7 @@ def build(output_root: Path, source_root: Path = ROOT) -> None:
output_root / ".agents" / "plugins" / "marketplace.json",
{
"name": "sent",
"interface": {"displayName": "Sent"},
"interface": {"displayName": marketplace["display_name"]},
"plugins": [
{
"name": "sent",
Expand All @@ -174,7 +171,7 @@ def build(output_root: Path, source_root: Path = ROOT) -> None:
"name": "sent",
"owner": {"name": "Sent", "url": "https://sent.dm"},
"metadata": {
"description": "Official Sent skills and remote MCP integration.",
"description": marketplace["marketplace_description"],
"version": version,
},
"plugins": [
Expand Down
38 changes: 38 additions & 0 deletions scripts/test_contracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

import generate_adapters as GENERATOR
import repository_metadata as REPOSITORY_METADATA
import yaml


ROOT = Path(__file__).resolve().parents[1]
Expand Down Expand Up @@ -84,6 +85,43 @@ def test_version_change_propagates_to_generated_manifests(self) -> None:
self.assertEqual(marketplace["metadata"]["version"], "9.8.7")


class SkillUiMetadataContractTests(unittest.TestCase):
def test_every_skill_has_unique_valid_openai_metadata(self) -> None:
metadata = REPOSITORY_METADATA.load_repository_metadata(ROOT)
display_names: set[str] = set()
descriptions: set[str] = set()
for name in metadata.skills:
path = SKILLS / name / "agents" / "openai.yaml"
with self.subTest(skill=name):
self.assertTrue(path.is_file(), path)
data = yaml.safe_load(path.read_text(encoding="utf-8"))
interface = data["interface"]
display_name = interface["display_name"].strip()
description = interface["short_description"].strip()
prompt = interface["default_prompt"].strip()
self.assertTrue(display_name)
self.assertTrue(description)
self.assertNotIn(display_name.casefold(), display_names)
self.assertNotIn(description.casefold(), descriptions)
self.assertEqual(re.findall(r"\$[a-z0-9-]+", prompt), [f"${name}"])
display_names.add(display_name.casefold())
descriptions.add(description.casefold())

def test_marketplace_prompts_include_specialists(self) -> None:
metadata = REPOSITORY_METADATA.load_repository_metadata(ROOT)
path = ROOT / "adapter-sources" / "shared" / "marketplace.json"
catalog = json.loads(path.read_text(encoding="utf-8"))
prompts = catalog["default_prompts"]
invoked = {
match.group(1)
for prompt in prompts
if (match := re.search(r"\$([a-z0-9-]+)", prompt))
}
specialists = set(metadata.skills) - set(metadata.tools_by_owner) - {"sent"}
self.assertGreaterEqual(len(invoked & specialists), 2)
self.assertEqual(catalog["website_url"], "https://github.com/sentdm/sent-plugin#readme")


class BundledExampleTests(unittest.TestCase):
def test_every_markdown_json_block_parses(self) -> None:
for path in SKILLS.rglob("*.md"):
Expand Down
42 changes: 38 additions & 4 deletions scripts/test_validation_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,17 @@ def missing_root_mcp(root: Path) -> None:


def missing_listing_url(root: Path) -> None:
path = root / "scripts" / "generate_adapters.py"
content = path.read_text(encoding="utf-8")
path.write_text(content.replace(' "websiteURL": "https://www.sent.dm",\n', ""), encoding="utf-8")
subprocess.run([sys.executable, str(path)], cwd=root, check=True, capture_output=True, text=True)
path = root / "adapter-sources" / "shared" / "marketplace.json"
catalog = json.loads(path.read_text(encoding="utf-8"))
catalog["website_url"] = "not-an-https-url"
path.write_text(json.dumps(catalog, indent=2) + "\n", encoding="utf-8")
subprocess.run(
[sys.executable, str(root / "scripts" / "generate_adapters.py")],
cwd=root,
check=True,
capture_output=True,
text=True,
)


def missing_readme_catalog_entry(root: Path) -> None:
Expand All @@ -99,6 +106,29 @@ def weak_skill_discovery_description(root: Path) -> None:
path.write_text("\n".join(lines) + "\n", encoding="utf-8")


def missing_skill_ui_metadata(root: Path) -> None:
(root / "packages" / "sent" / "skills" / "sent" / "agents" / "openai.yaml").unlink()


def wrong_skill_default_prompt(root: Path) -> None:
path = root / "packages" / "sent" / "skills" / "sent-analytics" / "agents" / "openai.yaml"
content = path.read_text(encoding="utf-8")
path.write_text(content.replace("$sent-analytics", "$sent-messaging"), encoding="utf-8")


def duplicate_skill_display_name(root: Path) -> None:
path = root / "packages" / "sent" / "skills" / "sent-analytics" / "agents" / "openai.yaml"
content = path.read_text(encoding="utf-8")
path.write_text(content.replace('display_name: "Sent Analytics"', 'display_name: "Sent Account Readiness"'), encoding="utf-8")


def unsafe_marketplace_prompt(root: Path) -> None:
path = root / "adapter-sources" / "shared" / "marketplace.json"
catalog = json.loads(path.read_text(encoding="utf-8"))
catalog["default_prompts"][0] = "Use $sent-account-readiness to send a message."
path.write_text(json.dumps(catalog, indent=2) + "\n", encoding="utf-8")


def wrong_openai_test_count(root: Path) -> None:
path = root / "chatgpt-app-submission.json"
submission = json.loads(path.read_text(encoding="utf-8"))
Expand Down Expand Up @@ -175,6 +205,10 @@ def contract_manifest_drift(root: Path) -> None:
("required listing URLs", missing_listing_url, "Codex websiteURL must be an HTTPS URL"),
("README skill catalog coverage", missing_readme_catalog_entry, "skill catalog does not link"),
("skill discovery descriptions", weak_skill_discovery_description, "discovery description must explain"),
("skill UI metadata coverage", missing_skill_ui_metadata, "missing agents/openai.yaml"),
("exact skill prompt invocation", wrong_skill_default_prompt, "must invoke exactly $sent-analytics"),
("unique skill display names", duplicate_skill_display_name, "display_name must be unique"),
("non-mutating marketplace prompt", unsafe_marketplace_prompt, "must be non-mutating"),
("OpenAI test counts", wrong_openai_test_count, "exactly three negative test cases"),
("unexpected MCP tool", unexpected_public_tool, "OpenAI submission tool set mismatch"),
("invalid MCP tool owner", invalid_tool_owner, "is not a canonical skill"),
Expand Down
Loading