From 64edb16135b80b88e524d85166541b3ee15db596 Mon Sep 17 00:00:00 2001 From: baskduf Date: Sun, 14 Jun 2026 19:18:56 +0900 Subject: [PATCH] feat: add Claude Code plugin packaging --- CHANGELOG.md | 25 ++++++ README.ja.md | 2 + README.ko.md | 2 + README.md | 3 +- README.zh-CN.md | 4 +- README.zh-TW.md | 4 +- agent-skills/.claude-plugin/plugin.json | 19 ++++ agent-skills/.codex-plugin/plugin.json | 2 +- docs/agent-skills-package.md | 72 ++++++++++++++- docs/component-map.md | 2 +- .../0008-universal-agent-skills-package.md | 5 +- .../0009-claude-code-plugin-marketplace.md | 65 ++++++++++++++ .../019-claude-code-plugin-marketplace.yaml | 89 +++++++++++++++++++ docs/validation.md | 10 ++- scripts/check_agent_skills_package.py | 80 +++++++++++++---- tests/test_agent_skills_package.py | 28 ++++++ 16 files changed, 383 insertions(+), 29 deletions(-) create mode 100644 agent-skills/.claude-plugin/plugin.json create mode 100644 docs/decisions/0009-claude-code-plugin-marketplace.md create mode 100644 docs/examples/task-outcomes/019-claude-code-plugin-marketplace.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f129d9..fb6fd32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,31 @@ Notable project changes should be recorded here before release tags are cut. ## Unreleased +## v0.1.13 - 2026-06-14 + +Patch release for Claude Code plugin distribution of the Universal Agent Skills +package. + +### Added + +- Claude Code plugin manifest at + `agent-skills/.claude-plugin/plugin.json` so the existing prompt-first skills + can be installed through Claude Code plugin marketplaces. +- Claude plugin packaging, local marketplace, validator, and namespaced + invocation guidance in `docs/agent-skills-package.md`. +- Decision memory for publishing Harness Agent Skills through Claude Code + plugin marketplaces. + +### Changed + +- Bump Agent Skills plugin manifests to `0.1.13` for aligned Codex and Claude + package releases. +- Extend Agent Skills package validation and tests to cover both Codex and + Claude plugin manifests, including optional `claude plugin validate` coverage + when Claude Code is available. +- Update README package summaries and validation docs for dual Codex and + Claude plugin packaging. + ## v0.1.12 - 2026-06-14 Minor release for the Universal Agent Skills package. This release exposes the diff --git a/README.ja.md b/README.ja.md index fac67b9..190f208 100644 --- a/README.ja.md +++ b/README.ja.md @@ -170,6 +170,8 @@ target-repository inspection の代替ではありません。 [`agent-skills/skills/`](agent-skills/skills/) 以下の shortcut skills を使います。 - Codex plugin として package する場合は [`agent-skills/.codex-plugin/plugin.json`](agent-skills/.codex-plugin/plugin.json) + を使い、Claude Code plugin として package する場合は + [`agent-skills/.claude-plugin/plugin.json`](agent-skills/.claude-plugin/plugin.json) を使います。 - Codex、Claude Code、repo-local installation notes は [`docs/agent-skills-package.md`](docs/agent-skills-package.md) を参照してください。 diff --git a/README.ko.md b/README.ko.md index 97506e1..8982f30 100644 --- a/README.ko.md +++ b/README.ko.md @@ -168,6 +168,8 @@ prompt-first workflows 위에 얹는 adapter layer이며, target-repository insp [`agent-skills/skills/`](agent-skills/skills/) 아래 shortcut skills를 사용하세요. - Codex plugin으로 패키징할 때는 [`agent-skills/.codex-plugin/plugin.json`](agent-skills/.codex-plugin/plugin.json)을 + 사용하고, Claude Code plugin으로 패키징할 때는 + [`agent-skills/.claude-plugin/plugin.json`](agent-skills/.claude-plugin/plugin.json)을 사용하세요. - Codex, Claude Code, repo-local 설치 안내는 [`docs/agent-skills-package.md`](docs/agent-skills-package.md)를 보세요. diff --git a/README.md b/README.md index 9fcc1c7..90a4949 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,8 @@ for target-repository inspection. - Use the shortcut skills under [`agent-skills/skills/`](agent-skills/skills/) when the runtime prefers one command per workflow. - Use [`agent-skills/.codex-plugin/plugin.json`](agent-skills/.codex-plugin/plugin.json) - when packaging the skills as a Codex plugin. + and [`agent-skills/.claude-plugin/plugin.json`](agent-skills/.claude-plugin/plugin.json) + when packaging the skills as Codex or Claude Code plugins. - See [`docs/agent-skills-package.md`](docs/agent-skills-package.md) for Codex, Claude Code, and repo-local installation notes. diff --git a/README.zh-CN.md b/README.zh-CN.md index 0241f69..16c9d45 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -166,7 +166,9 @@ inspection。 - 当 runtime 更适合每个 workflow 一个 command 时,使用 [`agent-skills/skills/`](agent-skills/skills/) 下的 shortcut skills。 - 作为 Codex plugin 打包时,使用 - [`agent-skills/.codex-plugin/plugin.json`](agent-skills/.codex-plugin/plugin.json)。 + [`agent-skills/.codex-plugin/plugin.json`](agent-skills/.codex-plugin/plugin.json); + 作为 Claude Code plugin 打包时,使用 + [`agent-skills/.claude-plugin/plugin.json`](agent-skills/.claude-plugin/plugin.json)。 - Codex、Claude Code 和 repo-local 安装说明见 [`docs/agent-skills-package.md`](docs/agent-skills-package.md)。 diff --git a/README.zh-TW.md b/README.zh-TW.md index 40e8084..c14cada 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -167,7 +167,9 @@ inspection。 - 當 runtime 比較適合每個 workflow 一個 command 時,使用 [`agent-skills/skills/`](agent-skills/skills/) 下的 shortcut skills。 - 作為 Codex plugin 打包時,使用 - [`agent-skills/.codex-plugin/plugin.json`](agent-skills/.codex-plugin/plugin.json)。 + [`agent-skills/.codex-plugin/plugin.json`](agent-skills/.codex-plugin/plugin.json); + 作為 Claude Code plugin 打包時,使用 + [`agent-skills/.claude-plugin/plugin.json`](agent-skills/.claude-plugin/plugin.json)。 - Codex、Claude Code 和 repo-local 安裝說明請見 [`docs/agent-skills-package.md`](docs/agent-skills-package.md)。 diff --git a/agent-skills/.claude-plugin/plugin.json b/agent-skills/.claude-plugin/plugin.json new file mode 100644 index 0000000..ce6232d --- /dev/null +++ b/agent-skills/.claude-plugin/plugin.json @@ -0,0 +1,19 @@ +{ + "name": "harness-agent-skills", + "displayName": "Harness Agent Skills", + "version": "0.1.13", + "description": "Portable Harness Starter Kit workflows for Claude Code.", + "author": { + "name": "Harnessworks", + "url": "https://github.com/harnessworks" + }, + "homepage": "https://github.com/harnessworks/harness-starter-kit", + "repository": "https://github.com/harnessworks/harness-starter-kit", + "license": "MIT", + "keywords": [ + "agent-skills", + "harness", + "claude-code", + "repository-guidance" + ] +} diff --git a/agent-skills/.codex-plugin/plugin.json b/agent-skills/.codex-plugin/plugin.json index 886bf1c..f71bc4a 100644 --- a/agent-skills/.codex-plugin/plugin.json +++ b/agent-skills/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "harness-agent-skills", - "version": "0.1.0", + "version": "0.1.13", "description": "Universal Agent Skills package for applying Harness Starter Kit workflows in coding-agent repositories.", "author": { "name": "Harnessworks", diff --git a/docs/agent-skills-package.md b/docs/agent-skills-package.md index 42e86e9..7c012a4 100644 --- a/docs/agent-skills-package.md +++ b/docs/agent-skills-package.md @@ -12,6 +12,8 @@ The package lives in [`agent-skills/`](../agent-skills/) and contains: fallback workflow references - [`agent-skills/.codex-plugin/plugin.json`](../agent-skills/.codex-plugin/plugin.json) for Codex plugin packaging +- [`agent-skills/.claude-plugin/plugin.json`](../agent-skills/.claude-plugin/plugin.json) + for Claude Code plugin packaging ## Design Contract @@ -93,8 +95,10 @@ restart Codex so the updated package is discovered. ## Claude Code Usage -Claude Code uses the same `SKILL.md` files. For a repo-local install, copy the -skills and references into the repository's Claude configuration directory: +Claude Code can use the package either as direct skills or as a plugin. + +For a repo-local direct-skill install, copy the skills and references into the +repository's Claude configuration directory: ```bash mkdir -p .claude/skills .claude/references @@ -115,6 +119,61 @@ The `harness` skill is the router, so users can invoke it with a subcommand such as `/harness doctor` in Claude Code. The shortcut skills are available for runtimes or teams that prefer one command per workflow. +For Claude Code plugin packaging, use [`agent-skills/`](../agent-skills/) as +the plugin root. The manifest at +[`agent-skills/.claude-plugin/plugin.json`](../agent-skills/.claude-plugin/plugin.json) +defines the Claude plugin metadata and lets Claude Code discover the packaged +skills directory. + +To test the package locally without installing from a remote marketplace: + +```bash +claude --plugin-dir ./agent-skills +``` + +Inside Claude Code, plugin skills are namespaced by plugin name. Invoke the +router as: + +```text +/harness-agent-skills:harness doctor +``` + +To test through a local Claude marketplace, copy the plugin into a temporary +marketplace root and create the Claude marketplace JSON file: + +```bash +MARKETPLACE_ROOT=/tmp/harness-agent-skills-claude-marketplace +rm -rf "$MARKETPLACE_ROOT" +mkdir -p "$MARKETPLACE_ROOT/.claude-plugin" "$MARKETPLACE_ROOT/plugins" +cp -R agent-skills "$MARKETPLACE_ROOT/plugins/harness-agent-skills" +cat > "$MARKETPLACE_ROOT/.claude-plugin/marketplace.json" <<'JSON' +{ + "name": "harnessworks", + "owner": { + "name": "Harnessworks" + }, + "description": "Harness Starter Kit Agent Skills for Claude Code.", + "plugins": [ + { + "name": "harness-agent-skills", + "source": "./plugins/harness-agent-skills", + "description": "Portable Harness Starter Kit workflows for Claude Code.", + "category": "Productivity" + } + ] +} +JSON +claude plugin validate "$MARKETPLACE_ROOT" +claude plugin validate "$MARKETPLACE_ROOT/plugins/harness-agent-skills" +claude plugin marketplace add "$MARKETPLACE_ROOT" +``` + +After adding the marketplace, install the plugin with: + +```bash +claude plugin install harness-agent-skills@harnessworks +``` + ## Validation Run the package drift check after changing skills, skill references, plugin @@ -124,5 +183,10 @@ metadata, or installation guidance: python3 scripts/check_agent_skills_package.py ``` -The check validates skill frontmatter, Codex metadata, plugin manifest fields, -reference coverage, router coverage, and documentation wiring. +The check validates skill frontmatter, Codex metadata, Codex and Claude plugin +manifest fields, reference coverage, router coverage, and documentation wiring. +When Claude Code is installed locally, also run: + +```bash +claude plugin validate agent-skills +``` diff --git a/docs/component-map.md b/docs/component-map.md index 55ab92b..6f0c3d1 100644 --- a/docs/component-map.md +++ b/docs/component-map.md @@ -21,7 +21,7 @@ This map connects harness engineering concepts to files in a target repository. | Harness update workflow | `/harness update` report | `commands/harness-update.md` | | Harness refresh workflow | `/harness refresh` report | `commands/harness-refresh.md` | | Harness change-set review | `/harness review` or `/harness review sub-agent` report | `commands/harness-review.md`, `docs/templates/harness-review-report.md` | -| Universal Agent Skills package | Codex and Claude Code skill adapters for `/harness ...` workflows | `agent-skills/`, `docs/agent-skills-package.md` | +| Universal Agent Skills package | Codex and Claude Code skill/plugin adapters for `/harness ...` workflows | `agent-skills/`, `agent-skills/.codex-plugin/plugin.json`, `agent-skills/.claude-plugin/plugin.json`, `docs/agent-skills-package.md` | | Agent Skills package validation | portable skill, metadata, manifest, and reference drift check | `scripts/check_agent_skills_package.py` | | Baseline harness score scan | six-element repository health and coupling scan | `scripts/harness_doctor.py` | | Deterministic benchmark tasks | repo-owned benchmark task definitions and project-specific oracles for `harness-agent-benchmark-runner` | `benchmarks/README.md`, `benchmarks/tasks/*.json` | diff --git a/docs/decisions/0008-universal-agent-skills-package.md b/docs/decisions/0008-universal-agent-skills-package.md index 31e8e64..92718fa 100644 --- a/docs/decisions/0008-universal-agent-skills-package.md +++ b/docs/decisions/0008-universal-agent-skills-package.md @@ -35,6 +35,7 @@ The package includes: - shortcut skills for each workflow - bundled workflow references for standalone installs - a Codex plugin manifest at `agent-skills/.codex-plugin/plugin.json` +- a Claude Code plugin manifest at `agent-skills/.claude-plugin/plugin.json` - validation through `scripts/check_agent_skills_package.py` The repository workflow docs remain canonical. Skills must first prefer target @@ -67,5 +68,5 @@ package's bundled fallback references. for the canonical command docs. - The package does not install itself into a user's Codex or Claude Code configuration; it documents copy and plugin-packaging paths. -- Public marketplace or registry publication should wait until local package - usage validates the invocation names and reference shape. +- Public marketplace publication remains a separate release operation from the + prompt-first package source. diff --git a/docs/decisions/0009-claude-code-plugin-marketplace.md b/docs/decisions/0009-claude-code-plugin-marketplace.md new file mode 100644 index 0000000..9b5dfb5 --- /dev/null +++ b/docs/decisions/0009-claude-code-plugin-marketplace.md @@ -0,0 +1,65 @@ +# 0009. Publish Harness Agent Skills Through Claude Code Plugins + +## Status + +Accepted + +## Date + +2026-06-14 + +## Context + +The Universal Agent Skills package is intentionally prompt-first: canonical +workflow behavior lives in `commands/`, `docs/adoption-workflow.md`, and the +bundled workflow references. Claude Code now supports plugin marketplaces for +versioned distribution of skills, with plugin manifests at +`agent-skills/.claude-plugin/plugin.json` and marketplace catalogs named +.claude-plugin/marketplace.json inside marketplace repositories. + +Shipping only direct-copy Claude skill instructions would keep the package +portable, but it would make team installation, version pinning, and updates +manual. Shipping a Claude plugin should not change the source-of-truth model or +turn the kit into an automated rewrite tool. + +## Decision + +Add Claude Code plugin metadata to the existing `agent-skills/` package and +publish it through the same public Harnessworks marketplace repository used for +the Codex package. + +The Claude release path is: + +1. update `agent-skills/.claude-plugin/plugin.json` +2. validate the package with `scripts/check_agent_skills_package.py` +3. validate the plugin with `claude plugin validate agent-skills` when Claude + Code is available +4. copy the released package into the marketplace repository +5. publish the Claude marketplace catalog with a relative plugin source +6. tag and release the marketplace repository + +Claude plugin installs use namespaced skill invocation such as +`/harness-agent-skills:harness doctor`. Direct skill installs can still use +`/harness doctor`. + +## Rationale + +- A Claude plugin marketplace gives Claude Code users the same install and + update ergonomics that Codex users get from the Codex marketplace. +- Keeping both runtime manifests in `agent-skills/` avoids forking the skill + body and bundled references. +- Namespaced Claude plugin commands prevent conflicts with project-local + skills while preserving the direct-copy `/harness ...` path. +- Requiring both repository validation and Claude's own validator catches drift + between prompt-first package content and runtime packaging metadata. + +## Consequences + +- Changes to `agent-skills/.claude-plugin/plugin.json` are release-affecting. +- Release notes must distinguish direct Claude skill invocation from Claude + plugin invocation. +- Marketplace release automation or docs should keep Codex root + marketplace JSON and the Claude marketplace catalog in the same repository + intentionally aligned. +- The community marketplace submission path remains optional and review-gated; + the first public release is the Harnessworks GitHub marketplace source. diff --git a/docs/examples/task-outcomes/019-claude-code-plugin-marketplace.yaml b/docs/examples/task-outcomes/019-claude-code-plugin-marketplace.yaml new file mode 100644 index 0000000..e686212 --- /dev/null +++ b/docs/examples/task-outcomes/019-claude-code-plugin-marketplace.yaml @@ -0,0 +1,89 @@ +schema_version: 1 + +target: + repository: harnessworks/harness-starter-kit + repository_ref: branch claude-agent-skills-package based on da3612753989 + stack_or_framework: Python unittest, Claude Code plugin manifest, Codex plugin manifest, Agent Skills, Markdown harness docs + date: 2026-06-14 + agent_or_model: Codex + reviewer: Codex primary agent with official Claude Code documentation lookup + +task: + id: claude-code-plugin-marketplace + run_id: harness-starter-kit-019 + prompt_summary: Publish the Universal Agent Skills package for Claude Code while preserving the prompt-first source model. + prompt_ref: current Codex thread request "claude도 출시하자" + prompt_hash: not recorded + comparable_task_group: harness-maintenance + condition: harnessed-only + expected_boundary: + - agent-skills/.claude-plugin/plugin.json + - agent-skills/.codex-plugin/plugin.json + - scripts/check_agent_skills_package.py + - tests/test_agent_skills_package.py + - docs/agent-skills-package.md + - docs/decisions/0008-universal-agent-skills-package.md + - docs/decisions/0009-claude-code-plugin-marketplace.md + - docs/component-map.md + - docs/validation.md + - CHANGELOG.md + - README.md + - README.ko.md + - README.ja.md + - README.zh-CN.md + - README.zh-TW.md + - docs/examples/task-outcomes/019-claude-code-plugin-marketplace.yaml + known_failure_mode: Runtime plugin publication can drift from prompt-first skill content, use the wrong Claude marketplace shape, or hide the difference between direct-skill and plugin-namespaced invocation. + +harness_context: + harness_doctor_score: 100/100 after implementation; this record is harness-maintenance evidence, not effectiveness proof + harness_source: + kit_url: https://github.com/harnessworks/harness-starter-kit + kit_commit: da3612753989 + source_tracking_ref: none; this repository is the kit source + relevant_instructions: + - AGENTS.md + - docs/agent-skills-package.md + - docs/validation.md + relevant_constraints: + - python3 scripts/check_agent_skills_package.py + - python3 -m unittest tests.test_agent_skills_package + - claude plugin validate agent-skills + - python3 scripts/check_decision_memory.py + relevant_memory_records: + - docs/decisions/0008-universal-agent-skills-package.md + - docs/decisions/0009-claude-code-plugin-marketplace.md + +outcome: + files_changed: + - agent-skills/.claude-plugin/plugin.json + - agent-skills/.codex-plugin/plugin.json + - scripts/check_agent_skills_package.py + - tests/test_agent_skills_package.py + - docs/agent-skills-package.md + - docs/decisions/0008-universal-agent-skills-package.md + - docs/decisions/0009-claude-code-plugin-marketplace.md + - docs/component-map.md + - docs/validation.md + - CHANGELOG.md + - README.md + - README.ko.md + - README.ja.md + - README.zh-CN.md + - README.zh-TW.md + - docs/examples/task-outcomes/019-claude-code-plugin-marketplace.yaml + wrong_file_edits: 0 + repeated_known_mistake: false + verification_command: python3 -m unittest discover -s tests && python3 -m py_compile scripts/apply_harness.py scripts/check_agent_skills_package.py scripts/check_docs_drift.py scripts/check_structure.py scripts/check_encoding_hygiene.py scripts/check_effectiveness_plan.py scripts/check_failure_memory.py scripts/check_decision_memory.py scripts/harness_doctor.py && python3 scripts/check_agent_skills_package.py && claude plugin validate agent-skills && python3 scripts/check_docs_drift.py && python3 scripts/check_structure.py && python3 scripts/check_encoding_hygiene.py && python3 scripts/check_effectiveness_plan.py && python3 scripts/check_failure_memory.py && python3 scripts/check_decision_memory.py && python3 scripts/harness_doctor.py --target . + first_pass_verification: + result: passed; unittest, py_compile, package check, Claude plugin validator, docs drift, structure, encoding, effectiveness, failure memory, decision memory, and Harness Doctor checks completed successfully + drift_violations_detected: [] + human_rework_minutes: 0 + reverted_files: [] + notes: The package keeps one prompt-first skill body and adds Claude Code plugin metadata plus validation and documentation for namespaced plugin invocation. Official Claude Code documentation was checked for plugin manifests, marketplace structure, validation commands, version behavior, and community submission paths. + +follow_up: + harness_change_needed: false + decision_or_failure_record: Decision record added in docs/decisions/0009-claude-code-plugin-marketplace.md; no failure record because this change adds a new distribution surface rather than fixing a recurring runtime failure. + include_in_effectiveness_report: false + include_in_comparable_product_task_count: false diff --git a/docs/validation.md b/docs/validation.md index cb9e396..2087acb 100644 --- a/docs/validation.md +++ b/docs/validation.md @@ -35,14 +35,20 @@ python -m unittest tests.test_profile_consistency Agent Skills package consistency is covered by `tests/test_agent_skills_package.py` and `scripts/check_agent_skills_package.py`. Run them directly when changing -`agent-skills/`, Codex plugin metadata, Claude Code skill guidance, or the -skills installation docs: +`agent-skills/`, Codex plugin metadata, Claude Code plugin metadata, skill +guidance, or the skills installation docs: ```powershell python -m unittest tests.test_agent_skills_package python scripts/check_agent_skills_package.py ``` +When Claude Code is installed locally, also run its plugin validator: + +```powershell +claude plugin validate agent-skills +``` + ## Fixture Smoke Tests Automated fixture smoke tests cover harness installation for: diff --git a/scripts/check_agent_skills_package.py b/scripts/check_agent_skills_package.py index 742b30e..346dc61 100644 --- a/scripts/check_agent_skills_package.py +++ b/scripts/check_agent_skills_package.py @@ -15,7 +15,9 @@ PACKAGE_ROOT = ROOT / "agent-skills" SKILLS_ROOT = PACKAGE_ROOT / "skills" REFERENCES_ROOT = PACKAGE_ROOT / "references" -PLUGIN_MANIFEST = PACKAGE_ROOT / ".codex-plugin" / "plugin.json" +CODEX_PLUGIN_MANIFEST = PACKAGE_ROOT / ".codex-plugin" / "plugin.json" +CLAUDE_PLUGIN_MANIFEST = PACKAGE_ROOT / ".claude-plugin" / "plugin.json" +PACKAGE_VERSION = "0.1.13" WORKFLOW_SKILLS = { "harness": None, @@ -63,40 +65,84 @@ def parse_frontmatter(path: Path) -> tuple[dict[str, str], str]: return metadata, body -def validate_plugin_manifest(errors: list[str]) -> None: - if not PLUGIN_MANIFEST.exists(): - errors.append(f"Missing plugin manifest: {PLUGIN_MANIFEST.relative_to(ROOT)}") - return - +def read_json(path: Path, label: str, errors: list[str]) -> dict | None: try: - manifest = json.loads(PLUGIN_MANIFEST.read_text(encoding="utf-8")) + return json.loads(path.read_text(encoding="utf-8")) except json.JSONDecodeError as exc: - errors.append(f"Invalid plugin manifest JSON: {exc}") + errors.append(f"Invalid {label} JSON: {exc}") + return None + + +def validate_codex_plugin_manifest(errors: list[str]) -> None: + if not CODEX_PLUGIN_MANIFEST.exists(): + errors.append( + f"Missing Codex plugin manifest: {CODEX_PLUGIN_MANIFEST.relative_to(ROOT)}" + ) + return + + manifest = read_json(CODEX_PLUGIN_MANIFEST, "Codex plugin manifest", errors) + if manifest is None: return expected = { "name": "harness-agent-skills", - "version": "0.1.0", + "version": PACKAGE_VERSION, "skills": "./skills/", "license": "MIT", } for key, value in expected.items(): if manifest.get(key) != value: - errors.append(f"plugin.json {key!r} should be {value!r}") + errors.append(f"Codex plugin.json {key!r} should be {value!r}") - if "[TODO:" in PLUGIN_MANIFEST.read_text(encoding="utf-8"): - errors.append("plugin.json contains TODO placeholders") + if "[TODO:" in CODEX_PLUGIN_MANIFEST.read_text(encoding="utf-8"): + errors.append("Codex plugin.json contains TODO placeholders") interface = manifest.get("interface", {}) for key in ("displayName", "shortDescription", "longDescription", "developerName"): if not interface.get(key): - errors.append(f"plugin.json interface.{key} is required") + errors.append(f"Codex plugin.json interface.{key} is required") prompts = interface.get("defaultPrompt") if not isinstance(prompts, list) or not prompts: - errors.append("plugin.json interface.defaultPrompt must include starter prompts") + errors.append( + "Codex plugin.json interface.defaultPrompt must include starter prompts" + ) elif not any("$harness" in prompt for prompt in prompts): - errors.append("plugin.json default prompts should mention $harness") + errors.append("Codex plugin.json default prompts should mention $harness") + + +def validate_claude_plugin_manifest(errors: list[str]) -> None: + if not CLAUDE_PLUGIN_MANIFEST.exists(): + errors.append( + f"Missing Claude plugin manifest: {CLAUDE_PLUGIN_MANIFEST.relative_to(ROOT)}" + ) + return + + manifest = read_json(CLAUDE_PLUGIN_MANIFEST, "Claude plugin manifest", errors) + if manifest is None: + return + + expected = { + "name": "harness-agent-skills", + "displayName": "Harness Agent Skills", + "version": PACKAGE_VERSION, + "license": "MIT", + } + for key, value in expected.items(): + if manifest.get(key) != value: + errors.append(f"Claude plugin.json {key!r} should be {value!r}") + + if "[TODO:" in CLAUDE_PLUGIN_MANIFEST.read_text(encoding="utf-8"): + errors.append("Claude plugin.json contains TODO placeholders") + + if not manifest.get("description"): + errors.append("Claude plugin.json description is required") + if manifest.get("repository") != "https://github.com/harnessworks/harness-starter-kit": + errors.append("Claude plugin.json repository should point to starter kit") + + keywords = manifest.get("keywords") + if not isinstance(keywords, list) or "claude-code" not in keywords: + errors.append("Claude plugin.json keywords should include claude-code") def validate_skill(skill_name: str, workflow_reference: str | None, errors: list[str]) -> None: @@ -240,6 +286,7 @@ def validate_documentation_wiring(errors: list[str]) -> None: ROOT / "README.md": "agent-skills/", ROOT / "docs" / "component-map.md": "agent-skills/", ROOT / "docs" / "validation.md": "check_agent_skills_package.py", + ROOT / "docs" / "agent-skills-package.md": ".claude-plugin/plugin.json", } for path, needle in expected_mentions.items(): if not path.exists() or needle not in path.read_text(encoding="utf-8"): @@ -253,7 +300,8 @@ def validate_package() -> list[str]: errors.append("Missing agent-skills package root") return errors - validate_plugin_manifest(errors) + validate_codex_plugin_manifest(errors) + validate_claude_plugin_manifest(errors) validate_references(errors) validate_installed_layout(errors) validate_workflow_safeguards(errors) diff --git a/tests/test_agent_skills_package.py b/tests/test_agent_skills_package.py index 5246921..34bf31e 100644 --- a/tests/test_agent_skills_package.py +++ b/tests/test_agent_skills_package.py @@ -28,10 +28,38 @@ def test_codex_plugin_manifest_points_to_packaged_skills(self) -> None: ) self.assertEqual("harness-agent-skills", manifest["name"]) + self.assertEqual("0.1.13", manifest["version"]) self.assertEqual("./skills/", manifest["skills"]) self.assertEqual("MIT", manifest["license"]) self.assertIn("$harness", " ".join(manifest["interface"]["defaultPrompt"])) + def test_claude_plugin_manifest_points_to_packaged_skills(self) -> None: + manifest = json.loads( + ( + REPO_ROOT / "agent-skills" / ".claude-plugin" / "plugin.json" + ).read_text(encoding="utf-8") + ) + + self.assertEqual("harness-agent-skills", manifest["name"]) + self.assertEqual("Harness Agent Skills", manifest["displayName"]) + self.assertEqual("0.1.13", manifest["version"]) + self.assertEqual("MIT", manifest["license"]) + self.assertEqual( + "https://github.com/harnessworks/harness-starter-kit", + manifest["repository"], + ) + self.assertIn("claude-code", manifest["keywords"]) + + def test_claude_plugin_validate_passes_when_claude_is_available(self) -> None: + if shutil.which("claude") is None: + self.skipTest("Claude Code CLI is not installed") + + subprocess.run( + ["claude", "plugin", "validate", "agent-skills"], + cwd=REPO_ROOT, + check=True, + ) + def test_router_and_shortcut_skills_cover_all_harness_commands(self) -> None: skills_root = REPO_ROOT / "agent-skills" / "skills" expected = {