diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json index 388b9e9..5db479d 100644 --- a/.claude-plugin/marketplace.json +++ b/.claude-plugin/marketplace.json @@ -1,5 +1,6 @@ { "name": "android-skills", + "description": "Google's official Android skills for agentic Android development.", "owner": { "name": "Google / Android" }, @@ -12,34 +13,6 @@ }, "category": "development", "source": "./", - "strict": false, - "skills": [ - "./build-system/agp/agp-9-upgrade", - "./camera/camerax", - "./device-ai/appfunctions", - "./device-ai/ml-kit-genai-prompt-api", - "./devtools/android-cli", - "./identity/restore-credentials", - "./identity/verified-email", - "./jetpack-compose/adaptive", - "./jetpack-compose/migration/migrate-xml-views-to-jetpack-compose", - "./jetpack-compose/theming/styles", - "./media/media3-cast-integration", - "./navigation/navigation-3", - "./navigation/navigation-event", - "./performance/r8-analyzer", - "./play/engage-sdk-integration", - "./play/play-billing-library-version-upgrade", - "./play/play-policy-insights", - "./profilers/android-profiler", - "./security/android-intent-security", - "./security/android-permissions-security", - "./system/edge-to-edge", - "./testing/testing-setup", - "./tv/leanback-to-compose-tv-migration", - "./wear/wear-compose-m3", - "./xr/display-glasses-with-jetpack-compose-glimmer" - ], "homepage": "https://github.com/android/skills", "license": "Apache-2.0" } diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..f8cc9ea --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,46 @@ +{ + "name": "android-skills", + "version": "1.0.13", + "displayName": "Android Skills", + "description": "Android skills are Google's official dedicated repository of AI-optimized, modular instructions and resources, to help LLMs better understand and execute specific patterns that follow the best practices and guidance on Android development. Android skills follow the open-standard agent skills - markdown files (SKILL.md) that provide a technical specification of a task, and ground LLMs with information on specialized domains and workflows.", + "author": { + "name": "Google / Android", + "url": "https://github.com/android" + }, + "homepage": "https://github.com/android/skills", + "repository": "https://github.com/android/skills", + "license": "Apache-2.0", + "keywords": [ + "android", + "kotlin", + "jetpack-compose", + "skills" + ], + "skills": [ + "./build-system/agp/agp-9-upgrade", + "./camera/camerax", + "./device-ai/appfunctions", + "./device-ai/ml-kit-genai-prompt-api", + "./devtools/android-cli", + "./identity/restore-credentials", + "./identity/verified-email", + "./jetpack-compose/adaptive", + "./jetpack-compose/migration/migrate-xml-views-to-jetpack-compose", + "./jetpack-compose/theming/styles", + "./media/media3-cast-integration", + "./navigation/navigation-3", + "./navigation/navigation-event", + "./performance/r8-analyzer", + "./play/engage-sdk-integration", + "./play/play-billing-library-version-upgrade", + "./play/play-policy-insights", + "./profilers/android-profiler", + "./security/android-intent-security", + "./security/android-permissions-security", + "./system/edge-to-edge", + "./testing/testing-setup", + "./tv/leanback-to-compose-tv-migration", + "./wear/wear-compose-m3", + "./xr/display-glasses-with-jetpack-compose-glimmer" + ] +} diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index 0a0c28d..1bcf118 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -21,25 +21,34 @@ jobs: ref: main token: ${{ secrets.ADR_GITHUB_BOT_PAT || secrets.GITHUB_TOKEN }} - - name: Update Codex Plugin Version + - name: Update Plugin Versions env: TAG_NAME: ${{ inputs.tag_name }} run: | VERSION="${TAG_NAME#v}" - echo "Updating .codex-plugin/plugin.json version to $VERSION" + echo "Updating plugin manifest versions to $VERSION" VERSION="$VERSION" python3 -c " import json import os + import pathlib version = os.environ['VERSION'] - path = '.codex-plugin/plugin.json' - with open(path, 'r') as f: - data = json.load(f) - data['version'] = version - with open(path, 'w') as f: - json.dump(data, f, indent=2) - f.write('\n') + + # Both manifests carry the version. Claude Code pins installs to the + # version in .claude-plugin/plugin.json, so leaving it stale means + # users never receive the new release. + for path in ('.claude-plugin/plugin.json', '.codex-plugin/plugin.json'): + p = pathlib.Path(path) + if not p.exists(): + raise FileNotFoundError(f'Required file {p} does not exist.') + with open(p, 'r') as f: + data = json.load(f) + data['version'] = version + with open(p, 'w') as f: + json.dump(data, f, indent=2) + f.write('\n') + print(f'Set {p} version to {version}') " - name: Commit and push updated version @@ -48,7 +57,7 @@ jobs: run: | git config user.name "android-devrel-github-bot" git config user.email "android-devrel-github-bot@users.noreply.github.com" - git add .codex-plugin/plugin.json + git add .claude-plugin/plugin.json .codex-plugin/plugin.json git commit -m "Bump plugin version to $TAG_NAME" || echo "No version change to commit" git push origin main diff --git a/.github/workflows/update-skills.yml b/.github/workflows/update-skills.yml index 315b022..6eb079c 100644 --- a/.github/workflows/update-skills.yml +++ b/.github/workflows/update-skills.yml @@ -75,20 +75,39 @@ jobs: skill_paths = sorted(list(set(skill_paths))) - # 1. Update .claude-plugin/marketplace.json in-place - claude_file = pathlib.Path('.claude-plugin/marketplace.json') - if not claude_file.exists(): - raise FileNotFoundError(f'Required file {claude_file} does not exist. Ensure you are running on the correct branch.') + # 1. Update .claude-plugin/plugin.json in-place. + # The skill list belongs in the plugin MANIFEST, never in the + # marketplace entry. Component fields such as 'skills' on the entry + # are rejected by Anthropic's plugin directory with + # MARKETPLACE_ENTRY_INLINE_MANIFEST. + claude_manifest = pathlib.Path('.claude-plugin/plugin.json') + if not claude_manifest.exists(): + raise FileNotFoundError(f'Required file {claude_manifest} does not exist. Ensure you are running on the correct branch.') + + with open(claude_manifest, 'r') as f: + data = json.load(f) + data['skills'] = skill_paths + with open(claude_manifest, 'w') as f: + json.dump(data, f, indent=2) + f.write('\n') + + # 2. Keep .claude-plugin/marketplace.json a pure catalogue. + # With a plugin.json present, strict:false plus any component field + # makes the plugin fail to load with 'conflicting manifests'. + claude_marketplace = pathlib.Path('.claude-plugin/marketplace.json') + if not claude_marketplace.exists(): + raise FileNotFoundError(f'Required file {claude_marketplace} does not exist. Ensure you are running on the correct branch.') - with open(claude_file, 'r') as f: + with open(claude_marketplace, 'r') as f: data = json.load(f) if 'plugins' in data and len(data['plugins']) > 0: - data['plugins'][0]['skills'] = skill_paths - with open(claude_file, 'w') as f: + for stale in ('skills', 'strict', 'commands', 'agents', 'hooks', 'outputStyles', 'themes'): + data['plugins'][0].pop(stale, None) + with open(claude_marketplace, 'w') as f: json.dump(data, f, indent=2) f.write('\n') - # 2. Update .codex-plugin/plugin.json in-place + # 3. Update .codex-plugin/plugin.json in-place codex_file = pathlib.Path('.codex-plugin/plugin.json') if not codex_file.exists(): raise FileNotFoundError(f'Required file {codex_file} does not exist. Ensure you are running on the correct branch.') diff --git a/README.md b/README.md index e0f6b74..dae981c 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,21 @@ android skills update --all android skills update wear-compose-m3 ``` +### Install as an agent plugin + +**Claude Code**: + +``` +/plugin install android-skills --marketplace android/skills +``` + +**Codex:** + +``` +codex plugin marketplace add android/skills +codex plugin add android-skills@android-skills +``` + ### Activate skills Your agent automatically activates skills that are relevant to your task. To use a skill, prompt your agent to complete a task that is related to the skill, for example "Make my app UI edge-to-edge." The agent should automatically find and use the skill if it has been installed.