fix: use scalar Claude agent tools (#2583)

Normalize scalar Claude agent tool metadata across validators, adapters, dashboards, and generated surfaces with regression coverage.
This commit is contained in:
Affaan Mustafa
2026-07-26 03:20:15 -07:00
committed by GitHub
parent f3afd59045
commit 6a9f075cd9
79 changed files with 515 additions and 87 deletions
+15
View File
@@ -55,6 +55,21 @@ This applies consistently across all component path fields.
---
## Agent `tools` Frontmatter: USE A SCALAR
The array rule above applies to `plugin.json`, not agent Markdown frontmatter.
Claude Code agent files use a comma-separated scalar for their tool allowlist:
```yaml
tools: Read, Glob, Grep
```
Do not use a YAML sequence such as `tools: [Read, Glob, Grep]`. Omitting the
`tools` field grants the agent access to all tools, but ECC agents declare
explicit allowlists and the repository validator requires the field.
---
## The `agents` Field: DO NOT ADD
> WARNING: **CRITICAL:** Do NOT add an `"agents"` field to `plugin.json`. The Claude Code plugin validator rejects it entirely.
+1 -1
View File
@@ -199,7 +199,7 @@ agents/your-agent-name.md
---
name: your-agent-name
description: What this agent does and when Claude should invoke it. Be specific!
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1152,7 +1152,7 @@ Subagents handle delegated tasks with limited scope. Example:
---
name: code-reviewer
description: Reviews code for quality, security, and maintainability
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: opus
---
+1 -1
View File
@@ -2,7 +2,7 @@
name: a11y-architect
description: Accessibility Architect specializing in WCAG 2.2 compliance for Web and Native platforms. Use PROACTIVELY when designing UI components, establishing design systems, or auditing code for inclusive user experiences.
model: sonnet
tools: ["Read", "Write", "Edit", "Grep", "Glob"]
tools: Read, Write, Edit, Grep, Glob
---
## Prompt Defense Baseline
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: agent-evaluator
description: Evaluates agent output against 5-axis quality rubric (accuracy, completeness, clarity, actionability, conciseness). Use after any non-trivial task when the user wants a quality assessment, or when the agent-self-evaluation skill is active. Produces structured scorecard with evidence and improvement suggestions.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: architect
description: Software architecture specialist for system design, scalability, and technical decision-making. Use PROACTIVELY when planning new features, refactoring large systems, or making architectural decisions.
tools: ["Read", "Grep", "Glob"]
tools: Read, Grep, Glob
model: opus
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: build-error-resolver
description: Build and TypeScript error resolution specialist. Use PROACTIVELY when build fails or type errors occur. Fixes build/type errors only with minimal diffs, no architectural edits. Focuses on getting the build green quickly.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: chief-of-staff
description: Personal communication chief of staff that triages email, Slack, LINE, and Messenger. Classifies messages into 4 tiers (skip/info_only/meeting_info/action_required), generates draft replies, and enforces post-send follow-through via hooks. Use when managing multi-channel communication workflows.
tools: ["Read", "Grep", "Glob", "Bash", "Edit", "Write"]
tools: Read, Grep, Glob, Bash, Edit, Write
model: sonnet
---
+1 -1
View File
@@ -2,7 +2,7 @@
name: code-architect
description: Designs feature architectures by analyzing existing codebase patterns and conventions, then providing implementation blueprints with concrete files, interfaces, data flow, and build order.
model: sonnet
tools: [Read, Grep, Glob, Bash]
tools: Read, Grep, Glob, Bash
---
## Prompt Defense Baseline
+1 -1
View File
@@ -2,7 +2,7 @@
name: code-explorer
description: Deeply analyzes existing codebase features by tracing execution paths, mapping architecture layers, and documenting dependencies to inform new development.
model: sonnet
tools: [Read, Grep, Glob]
tools: Read, Grep, Glob
---
## Prompt Defense Baseline
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: code-reviewer
description: Expert code review specialist. Proactively reviews code for quality, security, and maintainability. Use immediately after writing or modifying code. MUST BE USED for all code changes.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -2,7 +2,7 @@
name: code-simplifier
description: Simplifies and refines code for clarity, consistency, and maintainability while preserving behavior. Focus on recently modified code unless instructed otherwise.
model: sonnet
tools: [Read, Write, Edit, Bash, Grep, Glob]
tools: Read, Write, Edit, Bash, Grep, Glob
---
## Prompt Defense Baseline
+1 -1
View File
@@ -2,7 +2,7 @@
name: comment-analyzer
description: Analyze code comments for accuracy, completeness, maintainability, and comment rot risk.
model: haiku
tools: [Read, Grep, Glob]
tools: Read, Grep, Glob
---
## Prompt Defense Baseline
+1 -1
View File
@@ -2,7 +2,7 @@
name: conversation-analyzer
description: Use this agent when analyzing conversation transcripts to find behaviors worth preventing with hooks. Triggered by /hookify without arguments.
model: haiku
tools: [Read, Grep]
tools: Read, Grep
---
## Prompt Defense Baseline
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: cpp-build-resolver
description: C++ build, CMake, and compilation error resolution specialist. Fixes build errors, linker issues, and template errors with minimal changes. Use when C++ builds fail.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: cpp-reviewer
description: Expert C++ code reviewer specializing in memory safety, modern C++ idioms, concurrency, and performance. Use for all C++ code changes. MUST BE USED for C++ projects.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: csharp-reviewer
description: Expert C# code reviewer specializing in .NET conventions, async patterns, security, nullable reference types, and performance. Use for all C# code changes. MUST BE USED for C# projects.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: dart-build-resolver
description: Dart/Flutter build, analysis, and dependency error resolution specialist. Fixes `dart analyze` errors, Flutter compilation failures, pub dependency conflicts, and build_runner issues with minimal, surgical changes. Use when Dart/Flutter builds fail.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: database-reviewer
description: PostgreSQL database specialist for query optimization, schema design, security, and performance. Use PROACTIVELY when writing SQL, creating migrations, designing schemas, or troubleshooting database performance. Incorporates Supabase best practices.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: django-build-resolver
description: Django/Python build, migration, and dependency error resolution specialist. Fixes pip/Poetry errors, migration conflicts, import errors, Django configuration issues, and collectstatic failures with minimal changes. Use when Django setup or startup fails.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: django-reviewer
description: Expert Django code reviewer specializing in ORM correctness, DRF patterns, migration safety, security misconfigurations, and production-grade Django practices. Use for all Django code changes. MUST BE USED for Django projects.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: doc-updater
description: Documentation and codemap specialist. Use PROACTIVELY for updating codemaps and documentation. Runs /update-codemaps and /update-docs, generates docs/CODEMAPS/*, updates READMEs and guides.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: haiku
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: docs-lookup
description: When the user asks how to use a library, framework, or API or needs up-to-date code examples, use Context7 MCP to fetch current documentation and return answers with examples. Invoke for docs/API/setup questions.
tools: ["Read", "Grep", "mcp__context7__resolve-library-id", "mcp__context7__query-docs"]
tools: Read, Grep, mcp__context7__resolve-library-id, mcp__context7__query-docs
model: haiku
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: e2e-runner
description: End-to-end testing specialist using Vercel Agent Browser (preferred) with Playwright fallback. Use PROACTIVELY for generating, maintaining, and running E2E tests. Manages test journeys, quarantines flaky tests, uploads artifacts (screenshots, videos, traces), and ensures critical user flows work.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: fastapi-reviewer
description: Reviews FastAPI applications for async correctness, dependency injection, Pydantic schemas, security, OpenAPI quality, testing, and production readiness.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: flutter-reviewer
description: Flutter and Dart code reviewer. Reviews Flutter code for widget best practices, state management patterns, Dart idioms, performance pitfalls, accessibility, and clean architecture violations. Library-agnostic — works with any state management solution and tooling.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: fsharp-reviewer
description: Expert F# code reviewer specializing in functional idioms, type safety, pattern matching, computation expressions, and performance. Use for all F# code changes. MUST BE USED for F# projects.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: gan-evaluator
description: "GAN Harness — Evaluator agent. Tests the live running application via Playwright, scores against rubric, and provides actionable feedback to the Generator."
tools: ["Read", "Write", "Bash", "Grep", "Glob"]
tools: Read, Write, Bash, Grep, Glob
model: sonnet
color: red
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: gan-generator
description: "GAN Harness — Generator agent. Implements features according to the spec, reads evaluator feedback, and iterates until quality threshold is met."
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
color: green
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: gan-planner
description: "GAN Harness — Planner agent. Expands a one-line prompt into a full product specification with features, sprints, evaluation criteria, and design direction."
tools: ["Read", "Write", "Grep", "Glob"]
tools: Read, Write, Grep, Glob
model: sonnet
color: purple
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: go-build-resolver
description: Go build, vet, and compilation error resolution specialist. Fixes build errors, go vet issues, and linter warnings with minimal changes. Use when Go builds fail.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: go-reviewer
description: Expert Go code reviewer specializing in idiomatic Go, concurrency patterns, error handling, and performance. Use for all Go code changes. MUST BE USED for Go projects.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: harmonyos-app-resolver
description: HarmonyOS application development expert specializing in ArkTS and ArkUI. Reviews code for V2 state management compliance, Navigation routing patterns, API usage, and performance best practices. Use for HarmonyOS/OpenHarmony projects.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: harness-optimizer
description: Analyze and improve the local agent harness configuration for reliability, cost, and throughput.
tools: ["Read", "Grep", "Glob", "Bash", "Edit"]
tools: Read, Grep, Glob, Bash, Edit
model: sonnet
color: teal
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: healthcare-reviewer
description: Reviews healthcare application code for clinical safety, CDSS accuracy, PHI compliance, and medical data integrity. Specialized for EMR/EHR, clinical decision support, and health information systems.
tools: ["Read", "Grep", "Glob"]
tools: Read, Grep, Glob
model: opus
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: homelab-architect
description: Designs home and small-lab network plans from hardware inventory, goals, and operator experience level, with safe staged changes and rollback guidance.
tools: ["Read", "Grep"]
tools: Read, Grep
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: java-build-resolver
description: Java/Maven/Gradle build, compilation, and dependency error resolution specialist. Automatically detects Spring Boot or Quarkus and applies framework-specific fixes. Fixes build errors, Java compiler errors, and Maven/Gradle issues with minimal changes. Use when Java builds fail.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: java-reviewer
description: Expert Java code reviewer for Spring Boot and Quarkus projects. Automatically detects the framework and applies the appropriate review rules. Covers layered architecture, JPA/Panache, MongoDB, security, and concurrency. MUST BE USED for all Java code changes.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: kotlin-build-resolver
description: Kotlin/Gradle build, compilation, and dependency error resolution specialist. Fixes build errors, Kotlin compiler errors, and Gradle issues with minimal changes. Use when Kotlin builds fail.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: kotlin-reviewer
description: Kotlin and Android/KMP code reviewer. Reviews Kotlin code for idiomatic patterns, coroutine safety, Compose best practices, clean architecture violations, and common Android pitfalls.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: loop-operator
description: Operate autonomous agent loops, monitor progress, and intervene safely when loops stall.
tools: ["Read", "Grep", "Glob", "Bash", "Edit"]
tools: Read, Grep, Glob, Bash, Edit
model: sonnet
color: orange
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: marketing-agent
description: Marketing strategist and copywriter for campaign planning, audience research, positioning, copy creation, and content review. Covers landing pages, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use when the user wants to plan or execute a product launch or marketing campaign.
tools: ["Read", "Grep", "Glob", "WebSearch", "WebFetch"]
tools: Read, Grep, Glob, WebSearch, WebFetch
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: mle-reviewer
description: Production machine-learning engineering reviewer for data contracts, feature pipelines, training reproducibility, offline/online evaluation, model serving, monitoring, and rollback. Use when ML, MLOps, model training, inference, feature store, or evaluation code changes.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: network-architect
description: Designs enterprise or multi-site network architecture from requirements, using existing network skills for focused routing, validation, automation, and troubleshooting detail.
tools: ["Read", "Grep"]
tools: Read, Grep
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: network-config-reviewer
description: Reviews router and switch configurations for security, correctness, stale references, risky change-window commands, and missing operational guardrails.
tools: ["Read", "Grep"]
tools: Read, Grep
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: network-troubleshooter
description: Diagnoses network connectivity, routing, DNS, interface, and policy symptoms with a read-only OSI-layer workflow and evidence-backed root cause summary.
tools: ["Read", "Bash", "Grep"]
tools: Read, Bash, Grep
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: opensource-forker
description: Fork any project for open-sourcing. Copies files, strips secrets and credentials (20+ patterns), replaces internal references with placeholders, generates .env.example, and cleans git history. First stage of the opensource-pipeline skill.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: haiku
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: opensource-packager
description: Generate complete open-source packaging for a sanitized project. Produces CLAUDE.md, setup.sh, README.md, LICENSE, CONTRIBUTING.md, and GitHub issue templates. Makes any repo immediately usable with Claude Code. Third stage of the opensource-pipeline skill.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: haiku
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: opensource-sanitizer
description: Verify an open-source fork is fully sanitized before release. Scans for leaked secrets, PII, internal references, and dangerous files using 20+ regex patterns. Generates a PASS/FAIL/PASS-WITH-WARNINGS report. Second stage of the opensource-pipeline skill. Use PROACTIVELY before any public release.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: performance-optimizer
description: Performance analysis and optimization specialist. Use PROACTIVELY for identifying bottlenecks, optimizing slow code, reducing bundle sizes, and improving runtime performance. Profiling, memory leaks, render optimization, and algorithmic improvements.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: php-reviewer
description: Expert PHP code reviewer specializing in PSR-12 compliance, PHP type system, Eloquent ORM patterns, security, and performance. Use for all PHP code changes. MUST BE USED for PHP projects.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: planner
description: Expert planning specialist for complex features and refactoring. Use PROACTIVELY when users request feature implementation, architectural changes, or complex refactoring. Automatically activated for planning tasks.
tools: ["Read", "Grep", "Glob"]
tools: Read, Grep, Glob
model: opus
---
+1 -1
View File
@@ -2,7 +2,7 @@
name: pr-test-analyzer
description: Review pull request test coverage quality and completeness, with emphasis on behavioral coverage and real bug prevention.
model: sonnet
tools: [Read, Grep, Glob, Bash]
tools: Read, Grep, Glob, Bash
---
## Prompt Defense Baseline
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: python-reviewer
description: Expert Python code reviewer specializing in PEP 8 compliance, Pythonic idioms, type hints, security, and performance. Use for all Python code changes. MUST BE USED for Python projects.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: pytorch-build-resolver
description: PyTorch runtime, CUDA, and training error resolution specialist. Fixes tensor shape mismatches, device errors, gradient issues, DataLoader problems, and mixed precision failures with minimal changes. Use when PyTorch training or inference crashes.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: react-build-resolver
description: Diagnose and fix React build failures across Vite, webpack, Next.js, CRA, Parcel, esbuild, and Bun. Handles JSX/TSX compile errors, hydration mismatches, server/client component boundary failures, missing types, and bundler-specific configuration issues with minimal, surgical changes. MUST BE USED when a React build fails.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: react-reviewer
description: Expert React/JSX code reviewer specializing in hook correctness, render performance, server/client component boundaries, accessibility, and React-specific security. Use for any change touching .tsx/.jsx files or React component logic. MUST BE USED for React projects.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: refactor-cleaner
description: Dead code cleanup and consolidation specialist. Use PROACTIVELY for removing unused code, duplicates, and refactoring. Runs analysis tools (knip, depcheck, ts-prune) to identify dead code and safely removes it.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: rust-build-resolver
description: Rust build, compilation, and dependency error resolution specialist. Fixes cargo build errors, borrow checker issues, and Cargo.toml problems with minimal changes. Use when Rust builds fail.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: rust-reviewer
description: Expert Rust code reviewer specializing in ownership, lifetimes, error handling, unsafe usage, and idiomatic patterns. Use for all Rust code changes. MUST BE USED for Rust projects.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: security-reviewer
description: Security vulnerability detection and remediation specialist. Use PROACTIVELY after writing code that handles user input, authentication, API endpoints, or sensitive data. Flags secrets, SSRF, injection, unsafe crypto, and OWASP Top 10 vulnerabilities.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: seo-specialist
description: SEO specialist for technical SEO audits, on-page optimization, structured data, Core Web Vitals, and content/keyword mapping. Use for site audits, meta tag reviews, schema markup, sitemap and robots issues, and SEO remediation plans.
tools: ["Read", "Grep", "Glob", "WebSearch", "WebFetch"]
tools: Read, Grep, Glob, WebSearch, WebFetch
model: sonnet
---
+1 -1
View File
@@ -2,7 +2,7 @@
name: silent-failure-hunter
description: Review code for silent failures, swallowed errors, bad fallbacks, and missing error propagation.
model: sonnet
tools: [Read, Grep, Glob, Bash]
tools: Read, Grep, Glob, Bash
---
## Prompt Defense Baseline
+1 -1
View File
@@ -2,7 +2,7 @@
name: spec-miner
description: Extracts behavioral specs from existing codebases for OpenSpec. Produces flat Requirement and Invariant blocks with structured metadata (entities, enforced, id, test anchors). Outputs openspec/specs/<capability>/spec.md. Fully self-bootstrapping — no dependency on codebase-onboarding. Use when onboarding a brownfield project to spec-driven development.
model: opus
tools: ["Read", "Grep", "Glob", "Bash", "Write"]
tools: Read, Grep, Glob, Bash, Write
---
## Tool guardrails
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: swift-build-resolver
description: Swift/Xcode build, compilation, and dependency error resolution specialist. Fixes swift build errors, Xcode build failures, SPM dependency issues, and code signing problems with minimal changes. Use when Swift builds fail.
tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
tools: Read, Write, Edit, Bash, Grep, Glob
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: swift-reviewer
description: Expert Swift code reviewer specializing in protocol-oriented design, value semantics, ARC memory management, Swift Concurrency, and idiomatic patterns. Use for all Swift code changes. MUST BE USED for Swift projects.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: tdd-guide
description: Test-Driven Development specialist enforcing write-tests-first methodology. Use PROACTIVELY when writing new features, fixing bugs, or refactoring code. Ensures 80%+ test coverage.
tools: ["Read", "Write", "Edit", "Bash", "Grep"]
tools: Read, Write, Edit, Bash, Grep
model: sonnet
---
+1 -1
View File
@@ -2,7 +2,7 @@
name: type-design-analyzer
description: Analyze type design for encapsulation, invariant expression, usefulness, and enforcement.
model: sonnet
tools: [Read, Grep, Glob]
tools: Read, Grep, Glob
---
## Prompt Defense Baseline
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: typescript-reviewer
description: Expert TypeScript/JavaScript code reviewer specializing in type safety, async correctness, Node/web security, and idiomatic patterns. Use for all TypeScript and JavaScript code changes. MUST BE USED for TypeScript/JavaScript projects.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+1 -1
View File
@@ -1,7 +1,7 @@
---
name: vue-reviewer
description: Expert Vue.js code reviewer specializing in Composition API correctness, reactivity pitfalls, component architecture, template security, and Vue-specific performance. Use for any change touching .vue, .ts/.js files with Vue imports, or Vue ecosystem code (Pinia, Vue Router, Nuxt). MUST BE USED for Vue projects.
tools: ["Read", "Grep", "Glob", "Bash"]
tools: Read, Grep, Glob, Bash
model: sonnet
---
+25
View File
@@ -19,24 +19,44 @@ function extractFrontmatter(content) {
const frontmatter = {};
const duplicates = [];
const sequenceFields = [];
let currentTopLevelKey = null;
const lines = match[1].split(/\r?\n/);
for (const line of lines) {
if (/^\s*-\s+/.test(line)) {
if (currentTopLevelKey) {
sequenceFields.push(currentTopLevelKey);
}
continue;
}
// Only top-level keys are unique. Indented YAML belongs to nested values.
if (/^\s/.test(line)) continue;
if (!line.trim() || line.trim().startsWith('#')) continue;
currentTopLevelKey = null;
const colonIdx = line.indexOf(':');
if (colonIdx > 0) {
const key = line.slice(0, colonIdx).trim();
const value = line.slice(colonIdx + 1).trim();
currentTopLevelKey = key;
if (Object.prototype.hasOwnProperty.call(frontmatter, key)) {
duplicates.push(key);
}
frontmatter[key] = value;
if (value && '[!&*{|>'.includes(value[0])) {
sequenceFields.push(key);
}
}
}
Object.defineProperty(frontmatter, '__duplicates__', {
value: duplicates,
enumerable: false,
});
Object.defineProperty(frontmatter, '__sequenceFields__', {
value: sequenceFields,
enumerable: false,
});
return frontmatter;
}
@@ -79,6 +99,11 @@ function validateAgents() {
}
}
if (frontmatter.__sequenceFields__.includes('tools')) {
console.error(`ERROR: ${file} - Agent tools must be a comma-separated scalar, not a YAML sequence`);
hasErrors = true;
}
// Validate model is a known value
if (frontmatter.model && !VALID_MODELS.includes(frontmatter.model)) {
console.error(`ERROR: ${file} - Invalid model '${frontmatter.model}'. Must be one of: ${VALID_MODELS.join(', ')}`);
+6 -1
View File
@@ -12,6 +12,7 @@
const fs = require('fs');
const path = require('path');
const http = require('http');
const { normalizeAgentTools } = require('./lib/agent-tools');
function parsePort(v) {
const n = parseInt(String(v), 10);
@@ -31,7 +32,11 @@ function readFrontmatter(p) {
const s = l.indexOf(':'); if (s <= 0) continue;
let k = l.slice(0, s).trim(), v = l.slice(s + 1).trim();
if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) v = v.slice(1, -1);
if (v.startsWith('[') && v.endsWith(']')) { try { v = JSON.parse(v); } catch { v = v.slice(1, -1).split(',').map(x => x.trim().replace(/["']/g, '')); } }
if (k === 'tools') {
v = normalizeAgentTools(v);
} else if (v.startsWith('[') && v.endsWith(']')) {
try { v = JSON.parse(v); } catch { v = v.slice(1, -1).split(',').map(x => x.trim().replace(/["']/g, '')); }
}
fm[k] = v;
}
fm._body = c.replace(/^---[\s\S]*?---\n*/, '').trim();
+3 -14
View File
@@ -3,6 +3,7 @@
const fs = require('fs');
const path = require('path');
const { normalizeAgentTools } = require('./lib/agent-tools');
const TOOL_NAME_MAP = new Map([
['Read', 'read_file'],
@@ -53,25 +54,13 @@ function ensureDirectory(dirPath) {
}
}
function stripQuotes(value) {
return value.trim().replace(/^['"]|['"]$/g, '');
}
function parseToolList(line) {
const match = line.match(/^(\s*tools\s*:\s*)\[(.*)\]\s*$/);
const match = line.match(/^\s*tools\s*:\s*(.*)$/);
if (!match) {
return null;
}
const rawItems = match[2].trim();
if (!rawItems) {
return [];
}
return rawItems
.split(',')
.map(part => stripQuotes(part))
.filter(Boolean);
return normalizeAgentTools(match[1]);
}
function adaptToolName(toolName) {
+5
View File
@@ -2,6 +2,7 @@
const fs = require('fs');
const path = require('path');
const { normalizeAgentTools } = require('./agent-tools');
/**
* Parse YAML frontmatter from a markdown string.
@@ -35,6 +36,10 @@ function parseFrontmatter(content) {
value = value.slice(1, -1);
}
if (key === 'tools') {
value = normalizeAgentTools(value);
}
frontmatter[key] = value;
}
+97
View File
@@ -0,0 +1,97 @@
'use strict';
function stripSurroundingQuotes(value) {
const trimmed = value.trim();
const quote = trimmed[0];
if ((quote === '"' || quote === "'") && trimmed.endsWith(quote)) {
return trimmed.slice(1, -1).trim();
}
return trimmed;
}
function splitTopLevelToolList(value) {
const items = [];
const delimiters = [];
let quote = null;
let escaped = false;
let itemStart = 0;
for (let index = 0; index < value.length; index += 1) {
const character = value[index];
if (quote) {
if (escaped) {
escaped = false;
} else if (character === '\\') {
escaped = true;
} else if (character === quote) {
quote = null;
}
continue;
}
if (character === '"' || character === "'") {
quote = character;
continue;
}
if (character === '(' || character === '[' || character === '{') {
delimiters.push(character);
continue;
}
const expectedOpener = {
')': '(',
']': '[',
'}': '{',
}[character];
if (expectedOpener && delimiters.at(-1) === expectedOpener) {
delimiters.pop();
continue;
}
if (character === ',' && delimiters.length === 0) {
items.push(value.slice(itemStart, index));
itemStart = index + 1;
}
}
items.push(value.slice(itemStart));
return items;
}
/**
* Normalize Claude agent frontmatter tools to the array shape used internally.
*
* Claude Code expects tools to be a comma-separated scalar. Flow sequences are
* still accepted here so ECC can read legacy or harness-adapted agent files.
*/
function normalizeAgentTools(value) {
if (Array.isArray(value)) {
return value
.filter(item => typeof item === 'string')
.map(stripSurroundingQuotes)
.filter(Boolean);
}
if (typeof value !== 'string') {
return [];
}
const trimmed = value.trim();
const listValue = trimmed.startsWith('[') && trimmed.endsWith(']')
? trimmed.slice(1, -1)
: stripSurroundingQuotes(trimmed);
if (!listValue.trim()) {
return [];
}
return splitTopLevelToolList(listValue)
.map(stripSurroundingQuotes)
.filter(Boolean);
}
module.exports = {
normalizeAgentTools,
};
+175
View File
@@ -0,0 +1,175 @@
/**
* Focused tests for validate-agents.js tools frontmatter rules.
*
* Run with: node tests/ci/validate-agents-tools.test.js
*/
const assert = require('assert');
const path = require('path');
const fs = require('fs');
const os = require('os');
const { execFileSync } = require('child_process');
const validatorsDir = path.join(__dirname, '..', '..', 'scripts', 'ci');
const repoRoot = path.join(__dirname, '..', '..');
const canonicalAgentsDir = path.join(repoRoot, 'agents');
function test(name, fn) {
try {
fn();
console.log(` \u2713 ${name}`);
return true;
} catch (err) {
console.log(` \u2717 ${name}`);
console.log(` Error: ${err.message}`);
return false;
}
}
function createTestDir() {
return fs.mkdtempSync(path.join(os.tmpdir(), 'validate-agents-tools-test-'));
}
function cleanupTestDir(testDir) {
fs.rmSync(testDir, { recursive: true, force: true });
}
function stripShebang(source) {
let s = source;
if (s.charCodeAt(0) === 0xFEFF) s = s.slice(1);
if (s.startsWith('#!')) {
const nl = s.indexOf('\n');
s = nl === -1 ? '' : s.slice(nl + 1);
}
return s;
}
function runSourceViaTempFile(source) {
const tmpFile = path.join(repoRoot, `.tmp-validator-${Date.now()}-${Math.random().toString(36).slice(2)}.js`);
try {
fs.writeFileSync(tmpFile, source, 'utf8');
const stdout = execFileSync('node', [tmpFile], {
encoding: 'utf8',
stdio: ['pipe', 'pipe', 'pipe'],
timeout: 10000,
cwd: repoRoot,
});
return { code: 0, stdout, stderr: '' };
} catch (err) {
return {
code: err.status || 1,
stdout: err.stdout || '',
stderr: err.stderr || '',
};
} finally {
fs.rmSync(tmpFile, { force: true });
}
}
function runValidatorWithDir(validatorName, dirConstant, overridePath) {
const validatorPath = path.join(validatorsDir, `${validatorName}.js`);
let source = fs.readFileSync(validatorPath, 'utf8');
source = stripShebang(source);
const dirRegex = new RegExp(`const ${dirConstant} = .*?;`);
source = source.replace(dirRegex, `const ${dirConstant} = ${JSON.stringify(overridePath)};`);
return runSourceViaTempFile(source);
}
function readCanonicalAgent(file) {
const resolvedPath = path.resolve(canonicalAgentsDir, file);
const agentsRoot = path.resolve(canonicalAgentsDir);
assert.ok(
resolvedPath.startsWith(`${agentsRoot}${path.sep}`),
`${file} should resolve inside the canonical agents directory`
);
return fs.readFileSync(resolvedPath, 'utf8');
}
function runTests() {
console.log('\n=== Testing validate-agents tools frontmatter ===\n');
let passed = 0;
let failed = 0;
if (test('canonical agents declare tools as comma-separated scalars', () => {
const agentFiles = fs.readdirSync(canonicalAgentsDir).filter(file => file.endsWith('.md'));
for (const file of agentFiles) {
const content = readCanonicalAgent(file);
const frontmatter = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
assert.ok(frontmatter, `${file} should have frontmatter`);
const toolsLine = frontmatter[1].match(/^tools:\s*(.+)$/m);
assert.ok(toolsLine, `${file} should declare a non-empty tools scalar`);
assert.ok(
!toolsLine[1].trim().startsWith('['),
`${file} should use comma-separated scalar tools, not a YAML sequence`
);
}
})) passed++; else failed++;
if (test('accepts comma-separated scalar agent tools', () => {
const testDir = createTestDir();
try {
fs.writeFileSync(path.join(testDir, 'scalar-tools.md'), '---\nmodel: sonnet\ntools: Read, Glob, Grep\n---\n# Agent');
const result = runValidatorWithDir('validate-agents', 'AGENTS_DIR', testDir);
assert.strictEqual(result.code, 0, `Should accept scalar tools, got stderr: ${result.stderr}`);
} finally {
cleanupTestDir(testDir);
}
})) passed++; else failed++;
if (test('rejects YAML sequence-form agent tools', () => {
const testDir = createTestDir();
try {
fs.writeFileSync(path.join(testDir, 'sequence-tools.md'), '---\nmodel: sonnet\ntools: [Read, Glob, Grep]\n---\n# Agent');
const result = runValidatorWithDir('validate-agents', 'AGENTS_DIR', testDir);
assert.strictEqual(result.code, 1, 'Should reject sequence-form tools');
assert.ok(
result.stderr.includes('comma-separated scalar'),
`Should explain the supported tools format, got stderr: ${result.stderr}`
);
} finally {
cleanupTestDir(testDir);
}
})) passed++; else failed++;
if (test('rejects block sequence-form agent tools', () => {
const testDir = createTestDir();
try {
fs.writeFileSync(path.join(testDir, 'block-sequence-tools.md'), '---\nmodel: sonnet\ntools:\n - Read\n - Glob\n - Grep\n---\n# Agent');
const result = runValidatorWithDir('validate-agents', 'AGENTS_DIR', testDir);
assert.strictEqual(result.code, 1, 'Should reject block sequence-form tools');
assert.ok(
result.stderr.includes('comma-separated scalar'),
`Should explain the supported tools format, got stderr: ${result.stderr}`
);
} finally {
cleanupTestDir(testDir);
}
})) passed++; else failed++;
if (test('rejects explicitly tagged YAML sequence-form agent tools', () => {
const testDir = createTestDir();
try {
fs.writeFileSync(path.join(testDir, 'tagged-sequence-tools.md'), '---\nmodel: sonnet\ntools: !!seq [Read, Glob, Grep]\n---\n# Agent');
const result = runValidatorWithDir('validate-agents', 'AGENTS_DIR', testDir);
assert.strictEqual(result.code, 1, 'Should reject tagged sequence-form tools');
assert.ok(
result.stderr.includes('comma-separated scalar'),
`Should explain the supported tools format, got stderr: ${result.stderr}`
);
} finally {
cleanupTestDir(testDir);
}
})) passed++; else failed++;
console.log(`\nResults: Passed: ${passed}, Failed: ${failed}`);
process.exit(failed > 0 ? 1 : 0);
}
runTests();
+28 -1
View File
@@ -45,6 +45,29 @@ function runTests() {
passed++;
else failed++;
if (
test('parseFrontmatter normalizes comma-separated scalar tools to an array', () => {
const content = '---\nname: scalar-tools\ndescription: Scalar tools\ntools: Read, Glob, Grep\nmodel: sonnet\n---\n\nBody.';
const { frontmatter } = parseFrontmatter(content);
assert.deepStrictEqual(frontmatter.tools, ['Read', 'Glob', 'Grep']);
})
)
passed++;
else failed++;
if (
test('parseFrontmatter preserves commas inside scoped tool arguments', () => {
const content = '---\nname: scoped-tools\ndescription: Scoped tools\ntools: Agent(worker, researcher), Read, Bash\nmodel: sonnet\n---\n\nBody.';
const { frontmatter } = parseFrontmatter(content);
assert.deepStrictEqual(
frontmatter.tools,
['Agent(worker, researcher)', 'Read', 'Bash']
);
})
)
passed++;
else failed++;
if (
test('parseFrontmatter handles content without frontmatter', () => {
const content = 'Just a regular markdown file.';
@@ -155,7 +178,7 @@ function runTests() {
// Create a temp directory with test agent files
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-compress-test-'));
const agentContent = '---\nname: test-agent\ndescription: A test agent\ntools: ["Read"]\nmodel: haiku\n---\n\nTest agent body paragraph.\n\n## Details\nMore info.';
const agentContent = '---\nname: test-agent\ndescription: A test agent\ntools: Read\nmodel: haiku\n---\n\nTest agent body paragraph.\n\n## Details\nMore info.';
fs.writeFileSync(path.join(tmpDir, 'test-agent.md'), agentContent);
fs.writeFileSync(path.join(tmpDir, 'not-an-agent.txt'), 'ignored');
@@ -332,6 +355,10 @@ function runTests() {
if (!fs.existsSync(realAgentsDir)) return; // skip if not present
const result = buildAgentCatalog(realAgentsDir, { mode: 'catalog' });
assert.ok(result.agents.length > 0, 'Should find at least one agent');
assert.ok(
result.agents.every(agent => Array.isArray(agent.tools) && agent.tools.length > 0),
'Every catalog agent should retain its tools as a non-empty array'
);
assert.ok(result.stats.compressedBytes < result.stats.originalBytes, 'Catalog should be smaller than original');
// Verify significant compression ratio
const ratio = result.stats.compressedBytes / result.stats.originalBytes;
+62 -2
View File
@@ -36,6 +36,29 @@ function cleanup(dirPath) {
fs.rmSync(dirPath, { recursive: true, force: true });
}
function withTempDir(prefix, fn) {
const dirPath = createTempDir(prefix);
try {
return fn(dirPath);
} finally {
cleanup(dirPath);
}
}
test('withTempDir removes temp directories when the callback throws', () => {
let createdDir = '';
assert.throws(() => {
withTempDir('ecc-test-', dirPath => {
createdDir = dirPath;
assert.ok(fs.existsSync(createdDir));
throw new Error('fixture failure');
});
}, /fixture failure/);
assert.ok(createdDir);
assert.ok(!fs.existsSync(createdDir));
});
function writeFile(rootDir, relativePath, content) {
const targetPath = path.join(rootDir, relativePath);
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
@@ -125,6 +148,43 @@ test('readFrontmatter parses array tools field', () => {
cleanup(testRoot);
});
test('readFrontmatter preserves scoped tools in legacy flow sequences', () => {
const { readFrontmatter } = require(SCRIPT);
withTempDir('ecc-test-', tempDir => {
writeFile(tempDir, 'agent.md', [
'---',
'name: scoped-agent',
'tools: [Agent(worker, researcher), Read, Bash(git commit:*, git status:*)]',
'---',
'body',
].join('\n'));
const fm = readFrontmatter(path.join(tempDir, 'agent.md'));
assert.deepStrictEqual(fm.tools, [
'Agent(worker, researcher)',
'Read',
'Bash(git commit:*, git status:*)',
]);
});
});
test('readFrontmatter normalizes comma-separated scalar tools to an array', () => {
const { readFrontmatter } = require(SCRIPT);
testRoot = createTempDir('ecc-test-');
writeFile(testRoot, 'agent.md', [
'---',
'name: test-agent',
'tools: Bash, Read, Write',
'---',
'# Body',
].join('\n'));
const fm = readFrontmatter(path.join(testRoot, 'agent.md'));
assert.ok(Array.isArray(fm.tools));
assert.deepStrictEqual(fm.tools, ['Bash', 'Read', 'Write']);
cleanup(testRoot);
});
test('readFrontmatter handles quoted values', () => {
const { readFrontmatter } = require(SCRIPT);
testRoot = createTempDir('ecc-test-');
@@ -202,7 +262,7 @@ test('loadAgents loads agent markdown files', () => {
'name: typescript-reviewer',
'description: Reviews TypeScript code',
'model: claude-sonnet-4-6',
'tools: [Bash, Read, Write, Grep]',
'tools: Bash, Read, Write, Grep',
'---',
'# TypeScript Reviewer',
'You are a TypeScript code reviewer.',
@@ -212,7 +272,7 @@ test('loadAgents loads agent markdown files', () => {
'name: python-reviewer',
'description: Reviews Python code',
'model: claude-opus-4-8',
'tools: [Bash, Read]',
'tools: Bash, Read',
'---',
'# Python Reviewer',
].join('\n'));
+30
View File
@@ -99,6 +99,36 @@ function runTests() {
}
})) passed++; else failed++;
if (test('adapts comma-separated scalar Claude Code tools', () => {
const tempDir = createTempDir();
const agentsDir = path.join(tempDir, '.gemini', 'agents');
try {
writeAgent(
agentsDir,
'docs-lookup.md',
[
'---',
'name: docs-lookup',
'description: Documentation lookup agent',
'tools: Read, Grep, mcp__context7__resolve-library-id, mcp__context7__query-docs',
'model: sonnet',
'---',
'',
'Body'
].join('\n')
);
const result = run([agentsDir]);
assert.strictEqual(result.code, 0, result.stderr);
const updated = fs.readFileSync(path.join(agentsDir, 'docs-lookup.md'), 'utf8');
assert.ok(updated.includes('tools: ["read_file", "grep_search", "mcp_context7_resolve_library_id", "mcp_context7_query_docs"]'));
} finally {
cleanupTempDir(tempDir);
}
})) passed++; else failed++;
if (test('defaults to the cwd .gemini/agents directory', () => {
const tempDir = createTempDir();
const agentsDir = path.join(tempDir, '.gemini', 'agents');