From 976c08e4c35d4c9fe3596605af2d9baa858ca5ae Mon Sep 17 00:00:00 2001 From: jiangnan <1394485448@qq.com> Date: Fri, 6 Mar 2026 04:37:53 +0800 Subject: [PATCH 1/2] Add CI workflow to validate agent file format Adds a lint script and GitHub Actions workflow that checks agent markdown files for required YAML frontmatter fields (name, description, color) and recommends standard sections. Only changed files in PRs are validated to avoid blocking on pre-existing issues. --- .github/workflows/lint-agents.yml | 44 ++++++++++++ scripts/lint-agents.sh | 114 ++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 .github/workflows/lint-agents.yml create mode 100755 scripts/lint-agents.sh diff --git a/.github/workflows/lint-agents.yml b/.github/workflows/lint-agents.yml new file mode 100644 index 0000000..8baa37f --- /dev/null +++ b/.github/workflows/lint-agents.yml @@ -0,0 +1,44 @@ +name: Lint Agent Files + +on: + pull_request: + paths: + - 'design/**' + - 'engineering/**' + - 'marketing/**' + - 'product/**' + - 'project-management/**' + - 'testing/**' + - 'support/**' + - 'spatial-computing/**' + - 'specialized/**' + +jobs: + lint: + name: Validate agent frontmatter and structure + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get changed agent files + id: changed + run: | + FILES=$(git diff --name-only --diff-filter=ACMR origin/${{ github.base_ref }}...HEAD -- \ + 'design/*.md' 'engineering/*.md' 'marketing/*.md' 'product/*.md' \ + 'project-management/*.md' 'testing/*.md' 'support/*.md' \ + 'spatial-computing/*.md' 'specialized/*.md') + echo "files=$FILES" >> "$GITHUB_OUTPUT" + if [ -z "$FILES" ]; then + echo "No agent files changed." + else + echo "Changed files:" + echo "$FILES" + fi + + - name: Run agent linter + if: steps.changed.outputs.files != '' + run: | + chmod +x scripts/lint-agents.sh + ./scripts/lint-agents.sh ${{ steps.changed.outputs.files }} diff --git a/scripts/lint-agents.sh b/scripts/lint-agents.sh new file mode 100755 index 0000000..3ba121c --- /dev/null +++ b/scripts/lint-agents.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +# +# Validates agent markdown files: +# 1. YAML frontmatter must exist with name, description, color (ERROR) +# 2. Recommended sections checked but only warned (WARN) +# 3. File must have meaningful content +# +# Usage: ./scripts/lint-agents.sh [file ...] +# If no files given, scans all agent directories. + +set -euo pipefail + +AGENT_DIRS=( + design + engineering + marketing + product + project-management + testing + support + spatial-computing + specialized +) + +REQUIRED_FRONTMATTER=("name" "description" "color") +RECOMMENDED_SECTIONS=("Identity" "Core Mission" "Critical Rules") + +errors=0 +warnings=0 + +lint_file() { + local file="$1" + + # 1. Check frontmatter delimiters + local first_line + first_line=$(head -1 "$file") + if [[ "$first_line" != "---" ]]; then + echo "ERROR $file: missing frontmatter opening ---" + ((errors++)) + return + fi + + # Extract frontmatter (between first and second ---) + local frontmatter + frontmatter=$(awk 'NR==1{next} /^---$/{exit} {print}' "$file") + + if [[ -z "$frontmatter" ]]; then + echo "ERROR $file: empty or malformed frontmatter" + ((errors++)) + return + fi + + # 2. Check required frontmatter fields + for field in "${REQUIRED_FRONTMATTER[@]}"; do + if ! echo "$frontmatter" | grep -qE "^${field}:"; then + echo "ERROR $file: missing frontmatter field '${field}'" + ((errors++)) + fi + done + + # 3. Check recommended sections (warn only) + local body + body=$(awk 'BEGIN{n=0} /^---$/{n++; next} n>=2{print}' "$file") + + for section in "${RECOMMENDED_SECTIONS[@]}"; do + if ! echo "$body" | grep -qi "$section"; then + echo "WARN $file: missing recommended section '${section}'" + ((warnings++)) + fi + done + + # 4. Check file has meaningful content + if [[ $(echo "$body" | wc -w) -lt 50 ]]; then + echo "WARN $file: body seems very short (< 50 words)" + ((warnings++)) + fi +} + +# Collect files to lint +files=() +if [[ $# -gt 0 ]]; then + files=("$@") +else + for dir in "${AGENT_DIRS[@]}"; do + if [[ -d "$dir" ]]; then + while IFS= read -r f; do + files+=("$f") + done < <(find "$dir" -maxdepth 1 -name "*.md" -type f | sort) + fi + done +fi + +if [[ ${#files[@]} -eq 0 ]]; then + echo "No agent files found." + exit 1 +fi + +echo "Linting ${#files[@]} agent files..." +echo "" + +for file in "${files[@]}"; do + lint_file "$file" +done + +echo "" +echo "Results: ${errors} error(s), ${warnings} warning(s) in ${#files[@]} files." + +if [[ $errors -gt 0 ]]; then + echo "FAILED: fix the errors above before merging." + exit 1 +else + echo "PASSED" + exit 0 +fi From 2ded8e99a8a02726791056b937a7831a5da82d11 Mon Sep 17 00:00:00 2001 From: jiangnan <1394485448@qq.com> Date: Fri, 6 Mar 2026 06:03:35 +0800 Subject: [PATCH 2/2] Address review feedback on CI lint workflow - Fix ((errors++)) causing early exit under set -e - Fix command injection in workflow by using env variable - Add strategy/ directory to lint paths and AGENT_DIRS --- .github/workflows/lint-agents.yml | 7 +++++-- scripts/lint-agents.sh | 11 ++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/lint-agents.yml b/.github/workflows/lint-agents.yml index 8baa37f..7fffb1b 100644 --- a/.github/workflows/lint-agents.yml +++ b/.github/workflows/lint-agents.yml @@ -12,6 +12,7 @@ on: - 'support/**' - 'spatial-computing/**' - 'specialized/**' + - 'strategy/**' jobs: lint: @@ -28,7 +29,7 @@ jobs: FILES=$(git diff --name-only --diff-filter=ACMR origin/${{ github.base_ref }}...HEAD -- \ 'design/*.md' 'engineering/*.md' 'marketing/*.md' 'product/*.md' \ 'project-management/*.md' 'testing/*.md' 'support/*.md' \ - 'spatial-computing/*.md' 'specialized/*.md') + 'spatial-computing/*.md' 'specialized/*.md' 'strategy/*.md') echo "files=$FILES" >> "$GITHUB_OUTPUT" if [ -z "$FILES" ]; then echo "No agent files changed." @@ -39,6 +40,8 @@ jobs: - name: Run agent linter if: steps.changed.outputs.files != '' + env: + CHANGED_FILES: ${{ steps.changed.outputs.files }} run: | chmod +x scripts/lint-agents.sh - ./scripts/lint-agents.sh ${{ steps.changed.outputs.files }} + ./scripts/lint-agents.sh $CHANGED_FILES diff --git a/scripts/lint-agents.sh b/scripts/lint-agents.sh index 3ba121c..6922164 100755 --- a/scripts/lint-agents.sh +++ b/scripts/lint-agents.sh @@ -20,6 +20,7 @@ AGENT_DIRS=( support spatial-computing specialized + strategy ) REQUIRED_FRONTMATTER=("name" "description" "color") @@ -36,7 +37,7 @@ lint_file() { first_line=$(head -1 "$file") if [[ "$first_line" != "---" ]]; then echo "ERROR $file: missing frontmatter opening ---" - ((errors++)) + errors=$((errors + 1)) return fi @@ -46,7 +47,7 @@ lint_file() { if [[ -z "$frontmatter" ]]; then echo "ERROR $file: empty or malformed frontmatter" - ((errors++)) + errors=$((errors + 1)) return fi @@ -54,7 +55,7 @@ lint_file() { for field in "${REQUIRED_FRONTMATTER[@]}"; do if ! echo "$frontmatter" | grep -qE "^${field}:"; then echo "ERROR $file: missing frontmatter field '${field}'" - ((errors++)) + errors=$((errors + 1)) fi done @@ -65,14 +66,14 @@ lint_file() { for section in "${RECOMMENDED_SECTIONS[@]}"; do if ! echo "$body" | grep -qi "$section"; then echo "WARN $file: missing recommended section '${section}'" - ((warnings++)) + warnings=$((warnings + 1)) fi done # 4. Check file has meaningful content if [[ $(echo "$body" | wc -w) -lt 50 ]]; then echo "WARN $file: body seems very short (< 50 words)" - ((warnings++)) + warnings=$((warnings + 1)) fi }