diff --git a/.claude/commands/README.md b/.claude/commands/README.md new file mode 100644 index 0000000..7ce74b9 --- /dev/null +++ b/.claude/commands/README.md @@ -0,0 +1,349 @@ +# Claude Skills Slash Commands + +**Git workflow and quality assurance commands for the claude-skills repository.** + +--- + +## 🎯 Essential Commands + +### Git Workflow + +``` +/git:cm → Stage and commit (no push) +/git:cp → Stage, commit, and push +/git:pr → Create pull request +``` + +### Quality Gates + +``` +/review → Run local quality checks +/security-scan → Run security validation +``` + +--- + +## 📋 Git Commands + +### /git:cm - Commit (No Push) + +**Purpose**: Stage changes and create a conventional commit without pushing + +**Usage**: +``` +/git:cm +``` + +**What it does**: +1. Shows `git status --short` +2. Reviews each file diff for secrets +3. Stages files intentionally +4. Generates conventional commit message +5. Creates commit (no push) + +**When to use**: When you want to commit locally before pushing + +--- + +### /git:cp - Commit and Push + +**Purpose**: Complete git workflow with quality checks + +**Usage**: +``` +/git:cp +``` + +**What it does**: +1. Runs `/review` for quality checks +2. Stages changes +3. Creates conventional commit +4. Pushes to origin +5. Triggers CI workflows + +**When to use**: When ready to publish changes + +--- + +### /git:pr - Create Pull Request + +**Purpose**: Create a PR from current branch + +**Usage**: +``` +/git:pr # PR to main +/git:pr dev # PR to dev branch +``` + +**What it does**: +1. Verifies quality checks passed +2. Creates PR using template +3. Adds appropriate labels +4. Shares PR link + +**When to use**: After pushing changes and ready for review + +--- + +## 🔒 Quality Commands + +### /review - Local Quality Gate + +**Purpose**: Run all quality checks before pushing + +**Usage**: +``` +/review +``` + +**What it checks**: +- ✅ YAML linting (workflows) +- ✅ GitHub workflow schema validation +- ✅ Python syntax (all skill directories) +- ✅ Markdown link validation +- ✅ Dependency security audit (optional) + +**When to use**: Before committing/pushing changes + +--- + +### /security-scan - Security Validation + +**Purpose**: Scan for security issues + +**Usage**: +``` +/security-scan +``` + +**What it checks**: +- 🔍 Gitleaks (committed secrets detection) +- 🔍 Safety (Python dependency vulnerabilities) + +**When to use**: Before pushing, especially with new dependencies + +--- + +## 🔄 Complete Workflow + +### Standard Feature Development + +``` +# 1. Make changes to skills +[Edit files in marketing-skill/, product-team/, etc.] + +# 2. Run quality checks +/review + +# 3. Run security scan +/security-scan + +# 4. Commit and push +/git:cp + +# 5. Create pull request +/git:pr + +# 6. Wait for: + - ✅ Claude Code Review comment + - ✅ CI Quality Gate passing + - ✅ Human approval + +# 7. Merge PR + - Issue auto-closes (if linked) + - Project board updates +``` + +--- + +## 💡 Quick Reference + +| Command | Stage | Commit | Push | Quality Check | Create PR | +|---------|-------|--------|------|---------------|-----------| +| **/git:cm** | ✅ | ✅ | ❌ | ❌ | ❌ | +| **/git:cp** | ✅ | ✅ | ✅ | ✅ | ❌ | +| **/git:pr** | ❌ | ❌ | ❌ | Verify | ✅ | +| **/review** | ❌ | ❌ | ❌ | ✅ | ❌ | +| **/security-scan** | ❌ | ❌ | ❌ | ✅ | ❌ | + +--- + +## 📊 Commit Message Format + +All commits follow **Conventional Commits**: + +``` +(): + +## Context +- Why this change was needed +- What problem it solves + +## Testing +- [ ] All Python scripts tested +- [ ] Skills validated with Claude +- [ ] /review passed +- [ ] /security-scan passed + +## Reviewers +- [ ] @username +``` + +**Types**: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert` + +**Scopes**: `marketing-skill`, `product-team`, `c-level-advisor`, `engineering-team`, `ra-qm-team`, `workflows`, `docs`, `ci` + +**Examples**: +``` +feat(marketing-skill): add LinkedIn content framework +fix(product-team): correct RICE prioritization calculation +docs(README): update skill installation instructions +ci(workflows): add auto-close issues on PR merge +``` + +--- + +## 🎯 Use Cases + +### Quick Fix + +``` +# Fix typo in skill +[Edit file] +/review # Quick check +/git:cp # Commit + push +``` + +### New Skill Addition + +``` +# Create new skill +[Create skill directory and files] +/review # Validate structure +/security-scan # Check for issues +/git:cm # Commit locally +[Test skill activation] +/git:cp # Push when ready +/git:pr # Create PR for review +``` + +### Major Feature with Multiple Skills + +``` +# Work on branch +git checkout -b feature/enterprise-skills + +# Add multiple skills +[Create skill 1] +/git:cm + +[Create skill 2] +/git:cm + +[Create skill 3] +/git:cm + +# Final quality check +/review +/security-scan + +# Push and create PR +git push origin feature/enterprise-skills +/git:pr + +# Or use /git:cp if you want to push single commit +``` + +--- + +## 🚨 Emergency Bypass + +### Skip Reviews (Emergency Only) + +If you need to bypass checks: + +```bash +# Method 1: Use --no-verify flag +git push --no-verify + +# Method 2: PR title bypass +[EMERGENCY] Fix critical bug + +# Method 3: PR label +Add label: emergency, skip-review, or hotfix +``` + +**Note**: These bypass automated reviews but manual review is still recommended. + +--- + +## 📖 Integration with Automation + +These commands work seamlessly with the GitHub automation: + +**After running `/git:cp`**: +- Triggers CI Quality Gate workflow +- Shows results in GitHub Actions + +**After running `/git:pr`**: +- Triggers Claude Code Review +- Runs CI Quality Gate +- Updates project board status + +**After merging PR**: +- Auto-closes linked issues +- Updates project board to "Done" +- Posts completion comments + +--- + +## 🔗 Related Documentation + +- **Automation Setup**: `.github/AUTOMATION_SETUP.md` +- **PR Template**: `.github/pull_request_template.md` +- **Commit Template**: `.github/commit-template.txt` +- **Workflow Guide**: See factory project for detailed reference + +--- + +## 📍 Command Locations + +``` +.claude/commands/ +├── git/ +│ ├── cm.md # Commit (no push) +│ ├── cp.md # Commit and push +│ └── pr.md # Create PR +├── review.md # Quality checks +├── security-scan.md # Security validation +└── README.md # This file +``` + +--- + +## 💡 Tips + +**Before committing**: +- ✅ Run `/review` to catch issues early +- ✅ Run `/security-scan` if adding dependencies +- ✅ Test skills with Claude before pushing + +**When creating PRs**: +- ✅ Link related issues (`Fixes #123`) +- ✅ Fill out PR template completely +- ✅ Add appropriate labels +- ✅ Request specific reviewers + +**For quality**: +- ✅ Keep commits focused and atomic +- ✅ Write clear, descriptive commit messages +- ✅ Follow conventional commit format +- ✅ Update documentation with changes + +--- + +**Last Updated**: 2025-11-04 +**Version**: 1.0.0 +**Status**: ✅ Ready to use + +**Streamline your Git workflow with simple commands!** 🚀 diff --git a/.claude/commands/git/cm.md b/.claude/commands/git/cm.md new file mode 100644 index 0000000..6a91f54 --- /dev/null +++ b/.claude/commands/git/cm.md @@ -0,0 +1,14 @@ +--- +description: Stage working tree changes and create a Conventional Commit (no push). +--- + +1. Run `git status --short` to review pending changes. +2. For each file, open a diff (`git diff -- path/to/file`) and ensure no secrets or credentials are present. +3. Stage the files intentionally (`git add path/to/file`). Avoid `git add .` unless every change was reviewed. +4. Generate a Conventional Commit message (types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert). + - Commit subject ≤ 72 chars. + - Scope uses kebab-case (e.g., `feat(marketing-skill): ...`). + - Use `.github/commit-template.txt` for Context / Testing / Reviewers sections. +5. Run `git commit` and paste the generated message + context from the template. +6. Show the resulting commit (`git log -1 --stat`) and keep the commit hash handy. +7. **Do not push** in this command. Use `git/cp.md` when you're ready to publish. diff --git a/.claude/commands/git/cp.md b/.claude/commands/git/cp.md new file mode 100644 index 0000000..01da198 --- /dev/null +++ b/.claude/commands/git/cp.md @@ -0,0 +1,14 @@ +--- +description: Stage, commit, and push the current branch following git governance rules. +--- + +1. Run `/review` to ensure lint/tests/security checks pass locally. +2. Review and stage changes with `git add` (avoid staging generated or secret files). +3. Craft a Conventional Commit message (types: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert). + - Use `.github/commit-template.txt` and include Context / Testing / Reviewers blocks. + - Never add AI attribution strings to commits. +4. Commit with `git commit` using the prepared message. If commitlint fails, fix the message and retry. +5. Push to origin: `git push origin $(git branch --show-current)`. +6. Trigger remote checks for visibility: + - `gh workflow run ci-quality-gate.yml --ref $(git branch --show-current)` +7. Wait for workflow to finish (`gh run watch --workflow ci-quality-gate.yml`) before opening a pull request. diff --git a/.claude/commands/git/pr.md b/.claude/commands/git/pr.md new file mode 100644 index 0000000..54b9632 --- /dev/null +++ b/.claude/commands/git/pr.md @@ -0,0 +1,25 @@ +--- +description: Create a pull request from the current branch. +argument-hint: [target-branch] +--- + +## Variables + +TARGET_BRANCH: $1 (defaults to `main`) +SOURCE_BRANCH: current branch (`git branch --show-current`) + +## Workflow + +1. Ensure `/review` and `/security-scan` have passed locally. +2. Confirm `ci-quality-gate` workflow succeeded for `SOURCE_BRANCH`. +3. Create the PR using GitHub CLI: + ```bash + gh pr create \ + --base "$TARGET_BRANCH" \ + --head "$SOURCE_BRANCH" \ + --title "" \ + --body-file .github/pull_request_template.md + ``` + If no template exists, provide a summary referencing Context, Testing, and Security results. +4. Add labels (`gh pr edit --add-label "status: in-review"`). +5. Share the PR link with reviewers and ensure at least one human approval is obtained. diff --git a/.claude/commands/review.md b/.claude/commands/review.md new file mode 100644 index 0000000..8087d16 --- /dev/null +++ b/.claude/commands/review.md @@ -0,0 +1,33 @@ +--- +description: Run the local review gate before pushing. +--- + +Perform a complete review pass: + +1. Save work in progress and ensure the working tree is clean except for intentional changes. +2. Install tooling (only first run): + ```bash + pip install --upgrade pip + pip install yamllint==1.35.1 check-jsonschema==0.28.4 safety==3.2.4 + npm install --global markdown-link-check@3.12.2 + ``` +3. Lint GitHub workflows: + ```bash + yamllint -d '{extends: default, rules: {line-length: {max: 160}}}' .github/workflows + check-jsonschema --schema github-workflow --base-dir . .github/workflows/*.yml + ``` +4. Python syntax check: + ```bash + python -m compileall marketing-skill product-team c-level-advisor engineering-team ra-qm-team + ``` +5. Markdown sanity check: + ```bash + markdown-link-check README.md + ``` +6. Optional dependency audit (if `requirements*.txt` present): + ```bash + for f in $(find . -name "requirements*.txt" 2>/dev/null); do + safety check --full-report --file "$f" + done + ``` +7. Summarize results in the commit template's Testing section. Fix any failures before continuing. diff --git a/.claude/commands/security-scan.md b/.claude/commands/security-scan.md new file mode 100644 index 0000000..8c19bf8 --- /dev/null +++ b/.claude/commands/security-scan.md @@ -0,0 +1,22 @@ +--- +description: Run the security scan gate before pushing. +--- + +1. Ensure dependencies are installed: + ```bash + pip install safety==3.2.4 + brew install gitleaks # or appropriate package manager + ``` +2. Scan for committed secrets: + ```bash + gitleaks detect --verbose --redact + ``` + - Resolve any findings before continuing. +3. Audit Python dependencies (if requirements files exist): + ```bash + for f in $(find . -name "requirements*.txt" 2>/dev/null); do + safety check --full-report --file "$f" + done + ``` +4. Record results in the commit template's Testing section. +5. After a clean pass, proceed with commit and push workflow. diff --git a/.github/AUTOMATION_SETUP.md b/.github/AUTOMATION_SETUP.md new file mode 100644 index 0000000..6371b74 --- /dev/null +++ b/.github/AUTOMATION_SETUP.md @@ -0,0 +1,325 @@ +# GitHub Automation Setup Guide + +**Repository**: claude-skills +**Project Number**: 9 +**Status**: ⚙️ Configuration Required + +--- + +## Overview + +This repository includes AI-powered GitHub automation with: + +- ✅ **Claude Code Review** - Automatic PR reviews +- ✅ **Auto-Close Issues** - PRs auto-close linked issues when merged +- ✅ **Smart Sync** - Bidirectional issue ↔ project board synchronization +- ✅ **Quality Gates** - Automated linting, testing, security checks +- ✅ **Kill Switch** - Emergency workflow disable capability + +--- + +## Quick Start (15 minutes) + +### 1. Create Required Secrets + +You need **2 secrets** for full automation: + +#### ✅ CLAUDE_CODE_OAUTH_TOKEN (Already Configured) + +This secret is already set up for Claude Code reviews. + +#### ⚠️ PROJECTS_TOKEN (Required for Project Board Sync) + +**Create Personal Access Token:** + +1. Go to: https://github.com/settings/tokens/new +2. Configure: + - **Note**: "Claude Skills Project Board Access" + - **Expiration**: 90 days (recommended) + - **Select scopes**: + - ✅ `repo` (Full control of private repositories) + - ✅ `project` (Full control of projects) +3. Click "Generate token" +4. **Copy the token** (you won't see it again!) + +**Add to Repository:** + +1. Go to: https://github.com/alirezarezvani/claude-skills/settings/secrets/actions +2. Click "New repository secret" +3. **Name**: `PROJECTS_TOKEN` +4. **Value**: [Paste your token] +5. Click "Add secret" + +--- + +### 2. Create Project Board Labels + +Run these commands to create all required labels: + +```bash +# Status Labels (6) +gh label create "status: triage" --color "fbca04" --description "To Triage column" --repo alirezarezvani/claude-skills +gh label create "status: backlog" --color "d4c5f9" --description "Backlog column" --repo alirezarezvani/claude-skills +gh label create "status: ready" --color "0e8a16" --description "Ready column" --repo alirezarezvani/claude-skills +gh label create "status: in-progress" --color "1d76db" --description "In Progress column" --repo alirezarezvani/claude-skills +gh label create "status: in-review" --color "d876e3" --description "In Review column" --repo alirezarezvani/claude-skills +gh label create "status: done" --color "2ea44f" --description "Done column" --repo alirezarezvani/claude-skills + +# Priority Labels (4) +gh label create "P0" --color "b60205" --description "Critical priority" --repo alirezarezvani/claude-skills +gh label create "P1" --color "d93f0b" --description "High priority" --repo alirezarezvani/claude-skills +gh label create "P2" --color "fbca04" --description "Medium priority" --repo alirezarezvani/claude-skills +gh label create "P3" --color "0e8a16" --description "Low priority" --repo alirezarezvani/claude-skills + +# Type Labels (already exist - verify) +# bug, feature, documentation, enhancement, etc. +``` + +--- + +### 3. Configure Project Board + +Your project board columns must match these exact names: + +1. **To triage** +2. **Backlog** +3. **Ready** +4. **In Progress** +5. **In Review** +6. **Done** + +**Verify Configuration:** + +1. Go to: https://github.com/users/alirezarezvani/projects/9 +2. Check column names match exactly (case-sensitive) +3. Ensure "Status" field exists + +--- + +### 4. Test the Setup + +#### Test 1: Create Test Issue + +```bash +gh issue create \ + --title "Test: Automation Setup" \ + --body "Testing GitHub automation workflows" \ + --label "status: triage" \ + --repo alirezarezvani/claude-skills +``` + +**Expected Results:** +- ✅ Issue created +- ✅ Auto-added to project board (column: "To triage") +- ✅ Label synced + +#### Test 2: Change Issue Status + +```bash +# Get the issue number from step 1, then: +gh issue edit ISSUE_NUMBER --add-label "status: in-progress" --repo alirezarezvani/claude-skills +``` + +**Expected Results:** +- ✅ Issue moved to "In Progress" on project board +- ✅ Old status label removed +- ✅ New status label applied + +#### Test 3: Create Test PR + +```bash +# Create a branch +git checkout -b test/automation-setup +echo "# Test" > TEST.md +git add TEST.md +git commit -m "test: verify automation" +git push origin test/automation-setup + +# Create PR that fixes the test issue +gh pr create \ + --title "test: Verify automation workflows" \ + --body "Fixes #ISSUE_NUMBER" \ + --repo alirezarezvani/claude-skills +``` + +**Expected Results:** +- ✅ Claude review triggers (check Actions tab) +- ✅ CI Quality Gate runs +- ✅ When merged, issue auto-closes +- ✅ Project board updates to "Done" + +--- + +## Active Workflows + +| Workflow | Trigger | Status | +|----------|---------|--------| +| **claude-code-review.yml** | PR opened/updated | ✅ Active | +| **pr-issue-auto-close.yml** | PR merged | ✅ Active | +| **smart-sync.yml** | Issue/board changes | ⚠️ Requires PROJECTS_TOKEN | +| **ci-quality-gate.yml** | PR opened/updated | ✅ Active | + +--- + +## Emergency Procedures + +### 🚨 Disable All Workflows + +If something goes wrong: + +```bash +echo "STATUS: DISABLED" > .github/WORKFLOW_KILLSWITCH +git add .github/WORKFLOW_KILLSWITCH +git commit -m "emergency: Disable workflows" +git push origin main --no-verify +``` + +All workflows check this file and exit immediately if disabled. + +### ✅ Re-enable Workflows + +```bash +echo "STATUS: ENABLED" > .github/WORKFLOW_KILLSWITCH +git commit -am "chore: Re-enable workflows" +git push +``` + +--- + +## Usage Examples + +### Auto-Close Issues with PR + +In your PR description: + +```markdown +## Summary +Fixed the authentication bug + +## Related Issues +Fixes #123 +Closes #456 +``` + +When merged → Issues #123 and #456 automatically close with comment linking to PR. + +### Sync Issue Status + +**Option A - Update Label:** +```bash +gh issue edit 123 --add-label "status: in-review" +``` +→ Moves to "In Review" on project board + +**Option B - Update Board:** +``` +Drag issue to "In Review" column on project board +``` +→ Adds "status: in-review" label to issue + +--- + +## Troubleshooting + +### Smart Sync Not Working + +**Problem**: Labels not syncing with project board + +**Check:** +```bash +gh secret list --repo alirezarezvani/claude-skills | grep PROJECTS_TOKEN +``` + +**Solution**: If missing, add PROJECTS_TOKEN (see Step 1 above) + +### Claude Review Not Running + +**Problem**: No review comment on PR + +**Check:** +```bash +gh run list --workflow=claude-code-review.yml --limit 5 --repo alirezarezvani/claude-skills +``` + +**Solutions**: +- Verify CLAUDE_CODE_OAUTH_TOKEN exists +- Check workflow logs for errors +- Re-run workflow from Actions tab + +### Rate Limits + +**Check current limits:** +```bash +gh api rate_limit --jq '.resources.core.remaining, .resources.graphql.remaining' +``` + +**Rate Limit Info:** +- REST API: 5,000/hour +- GraphQL: 5,000/hour +- Workflows require 50+ remaining before executing + +--- + +## Maintenance + +### Weekly + +```bash +# Check failed runs +gh run list --status failure --limit 10 --repo alirezarezvani/claude-skills + +# Verify secrets valid +gh secret list --repo alirezarezvani/claude-skills +``` + +### Quarterly + +```bash +# Regenerate PROJECTS_TOKEN (expires every 90 days) +# 1. Create new token with same scopes +# 2. Update repository secret +# 3. Test with a sync operation +``` + +--- + +## Security Notes + +**4-Layer Security Model:** + +1. **GitHub Permissions** - Only team members trigger workflows +2. **Tool Restrictions** - Allowlist specific commands only +3. **Token Scoping** - Minimal permissions (repo + project) +4. **Branch Protection** - Required reviews, status checks + +**Kill Switch**: Emergency disable capability (WORKFLOW_KILLSWITCH file) + +--- + +## Next Steps + +1. ✅ Create PROJECTS_TOKEN secret +2. ✅ Create all required labels +3. ✅ Verify project board columns +4. ✅ Test with sample issue and PR +5. ✅ Monitor first few workflow runs +6. ✅ Document any project-specific customizations + +--- + +## Support + +**Documentation:** +- This setup guide +- Individual workflow files in `.github/workflows/` +- Factory reference: https://github.com/alirezarezvani/claude-code-skills-factory + +**Getting Help:** +- Create issue with `question` label +- Check workflow logs: `gh run view RUN_ID --log` +- Review troubleshooting section above + +--- + +**Last Updated**: 2025-11-04 +**Status**: Ready for configuration ⚙️ diff --git a/.github/WORKFLOW_KILLSWITCH b/.github/WORKFLOW_KILLSWITCH new file mode 100644 index 0000000..26d8b15 --- /dev/null +++ b/.github/WORKFLOW_KILLSWITCH @@ -0,0 +1 @@ +STATUS: ENABLED diff --git a/.github/branch-protection-config.json b/.github/branch-protection-config.json new file mode 100644 index 0000000..2d54bf5 --- /dev/null +++ b/.github/branch-protection-config.json @@ -0,0 +1,17 @@ +{ + "required_status_checks": { + "strict": true, + "contexts": [ + "claude-review" + ] + }, + "enforce_admins": true, + "required_pull_request_reviews": null, + "restrictions": null, + "allow_force_pushes": false, + "allow_deletions": false, + "block_creations": false, + "required_conversation_resolution": true, + "required_linear_history": false, + "lock_branch": false +} diff --git a/.github/commit-template.txt b/.github/commit-template.txt new file mode 100644 index 0000000..e0bb6a5 --- /dev/null +++ b/.github/commit-template.txt @@ -0,0 +1,14 @@ +(): + +## Context +- + +## Testing +- [ ] All Python scripts tested +- [ ] Skills validated with Claude +- [ ] Documentation updated +- [ ] Examples work as expected + +## Reviewers +- [ ] @ + diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 3b8d0b8..f603e33 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,183 +1,60 @@ -# Pull Request +## Summary + -## Description -**What does this PR do?** +## Context + -A clear and concise description of the changes. - -## Type of Change - -Select the type of change: -- [ ] New skill addition -- [ ] Skill enhancement/improvement -- [ ] Bug fix -- [ ] Documentation update -- [ ] Python script improvement -- [ ] Refactoring/optimization -- [ ] Other (specify) - -## Related Issue - -Fixes #(issue number) - -Or: Related to #(issue number) - ---- - -## Changes Made - -### Skills Added/Modified - -**Skill Name(s):** - -**What Changed:** -- Added: (new capabilities, scripts, references) -- Modified: (what was changed and why) -- Removed: (what was deprecated/removed and why) +## Changes + -### Python Scripts - -**New Scripts:** -- `script_name.py` - Purpose and functionality - -**Modified Scripts:** -- `existing_script.py` - Changes made - -### Documentation - -**Files Updated:** -- README.md - (what sections) -- SKILL.md - (what changed) -- Reference files - (which ones) - ---- +- ## Testing + -### Testing Performed +- [ ] Local quality checks passed (Python syntax, markdown links) +- [ ] All Python scripts tested and working +- [ ] Skills validated with Claude (if applicable) +- [ ] `ci-quality-gate` workflow will pass +- [ ] Manual testing completed -- [ ] Tested with Claude AI (uploaded SKILL.md and verified activation) -- [ ] Tested with Claude Code (loaded skill and ran workflows) -- [ ] All Python scripts run without errors -- [ ] Ran scripts with `--help` flag -- [ ] Tested JSON output (if applicable) -- [ ] All reference links work -- [ ] No broken relative paths +**Testing Details**: + -### Test Results -**Claude Activation:** -- [ ] Skill activates when appropriate -- [ ] Description triggers correctly -- [ ] Keywords help discovery +## Security + -**Python Scripts:** -```bash -# Commands run for testing -python scripts/tool.py --help -python scripts/tool.py test-input.txt -``` +- [ ] No secrets, credentials, or API keys committed +- [ ] No destructive commands in generated outputs +- [ ] Path traversal vulnerabilities checked +- [ ] Dependencies reviewed (if added) -**Results:** -``` -[Paste test output or describe results] -``` +## Documentation + + +- [ ] README.md updated (if applicable) +- [ ] CLAUDE.md updated (if applicable) +- [ ] Inline code comments added for complex logic +- [ ] CHANGELOG.md updated (if applicable) +- [ ] Skill SKILL.md files updated (if applicable) + +## Reviewers + + +- [ ] @ + +## Related Issues + + +Fixes # +Closes # +Related to # --- -## Quality Checklist - -### SKILL.md Quality - -- [ ] YAML frontmatter is valid -- [ ] `name` matches directory name -- [ ] `description` includes what, when, and keyword triggers -- [ ] `license: MIT` included -- [ ] `metadata` section complete (version, author, category, domain) -- [ ] Keywords section added -- [ ] SKILL.md length <200 lines (or justified if longer) -- [ ] Clear quick start section -- [ ] Core workflows documented -- [ ] Examples included - -### Python Scripts Quality (if applicable) - -- [ ] Production-ready code (not placeholders) -- [ ] CLI with `--help` support -- [ ] Proper error handling -- [ ] Clear docstrings -- [ ] Type hints used -- [ ] Standard library preferred -- [ ] Dependencies documented -- [ ] No hardcoded paths or credentials - -### Documentation Quality - -- [ ] All links work (no 404s) -- [ ] Markdown formatting correct -- [ ] No typos or grammar errors -- [ ] Code blocks have language specified -- [ ] Examples are realistic and complete -- [ ] Screenshots included where helpful - -### Repository Integration - -- [ ] Domain-specific README.md updated (if new skill) -- [ ] Main README.md updated (if new domain or major feature) -- [ ] CLAUDE.md updated (if changes affect development) -- [ ] CHANGELOG.md updated (in Unreleased section) - ---- - -## ROI & Value - -**Estimated Value of This Contribution:** - -**Time Savings:** -- Hours saved per month per user: (estimate) -- Number of potential users: (estimate) - -**Quality Improvements:** -- Specific quality gains: (describe) -- Measurable improvements: (quantify if possible) - -**Why This Matters:** -Brief explanation of the business/user value. - ---- - -## Screenshots - -If applicable, add screenshots to help explain your changes. - ---- - -## Additional Notes - -Any other information reviewers should know: -- Implementation decisions made -- Alternative approaches considered -- Known limitations -- Future enhancement ideas - ---- - -## Contributor Checklist - -**Before Submitting:** -- [ ] I have read [CONTRIBUTING.md](../CONTRIBUTING.md) -- [ ] I have followed the skill creation guidelines -- [ ] I have tested thoroughly -- [ ] I have updated all relevant documentation -- [ ] I have added my changes to CHANGELOG.md (Unreleased section) -- [ ] My code follows the repository's style guidelines -- [ ] All new Python scripts are production-ready -- [ ] I agree to the MIT License for my contributions - ---- - -**Thank you for contributing to Claude Skills Library!** 🚀 - -Your contribution helps make world-class expertise accessible to everyone through Claude AI. +**Type**: +**Scope**: diff --git a/.github/workflows/ci-quality-gate.yml b/.github/workflows/ci-quality-gate.yml new file mode 100644 index 0000000..484fa03 --- /dev/null +++ b/.github/workflows/ci-quality-gate.yml @@ -0,0 +1,91 @@ +--- +name: CI Quality Gate + +'on': + pull_request: + types: [opened, synchronize, reopened, ready_for_review] + workflow_dispatch: + inputs: + ref: + description: Branch to run quality gate against + required: false + repository_dispatch: + types: [ci-quality] + +concurrency: + group: quality-gate-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: true + +jobs: + quality: + name: Lint, Tests, Docs, Security + runs-on: ubuntu-latest + permissions: + contents: read + timeout-minutes: 25 + steps: + - name: Resolve ref + id: ref + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" && -n "${{ github.event.inputs.ref }}" ]]; then + echo "target_ref=${{ github.event.inputs.ref }}" >> "$GITHUB_OUTPUT" + elif [[ "${{ github.event_name }}" == "repository_dispatch" && -n "${{ github.event.client_payload.ref }}" ]]; then + echo "target_ref=${{ github.event.client_payload.ref }}" >> "$GITHUB_OUTPUT" + else + echo "target_ref=${{ github.head_ref || github.ref_name }}" >> "$GITHUB_OUTPUT" + fi + + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ steps.ref.outputs.target_ref }} + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install tooling + run: | + python -m pip install --upgrade pip + pip install yamllint==1.35.1 check-jsonschema==0.28.4 safety==3.2.4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: YAML lint (.github/workflows) + run: | + yamllint -d '{extends: default, rules: {line-length: {max: 160}}}' .github/workflows + + - name: Validate GitHub workflow schemas + run: | + check-jsonschema --schema github-workflow --base-dir . .github/workflows/*.yml + + - name: Python syntax check + run: | + python -m compileall marketing-skill product-team c-level-advisor engineering-team ra-qm-team || true + + - name: Safety dependency audit (requirements*.txt) + run: | + set -e + files=$(find . -name "requirements*.txt" 2>/dev/null || true) + if [[ -z "$files" ]]; then + echo "No requirements files found; skipping safety scan." + exit 0 + fi + for f in $files; do + echo "Auditing $f" + safety check --full-report --file "$f" || true + done + + - name: Markdown link spot-check + run: | + npx --yes markdown-link-check@3.12.2 README.md + + - name: Summarize results + if: always() + run: | + echo "Quality gate completed with status: ${{ job.status }}" diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 205b0fe..85862ea 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -1,39 +1,92 @@ +--- name: Claude Code Review -on: +'on': pull_request: types: [opened, synchronize] - # Optional: Only run on specific file changes - # paths: - # - "src/**/*.ts" - # - "src/**/*.tsx" - # - "src/**/*.js" - # - "src/**/*.jsx" + +# Prevent multiple review runs on rapid PR updates +concurrency: + group: claude-review-${{ github.event.pull_request.number }} + cancel-in-progress: true jobs: claude-review: - # Optional: Filter by PR author - # if: | - # github.event.pull_request.user.login == 'external-contributor' || - # github.event.pull_request.user.login == 'new-developer' || - # github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR' - + # Auto-review ALL pull requests with Claude + # BYPASS: Add [EMERGENCY], [SKIP REVIEW], or [HOTFIX] to PR title + # BYPASS: Or add 'emergency' or 'skip-review' label to PR runs-on: ubuntu-latest permissions: contents: read pull-requests: read issues: read - id-token: write + id-token: write # Required by Claude Code action for OIDC authentication steps: + - name: Check Workflow Kill Switch + run: | + if [ -f ".github/WORKFLOW_KILLSWITCH" ]; then + STATUS=$(grep "STATUS:" .github/WORKFLOW_KILLSWITCH | awk '{print $2}') + if [ "$STATUS" = "DISABLED" ]; then + echo "🛑 Workflows disabled by kill switch" + exit 0 + fi + fi + - name: Check for Review Bypass + id: bypass + run: | + PR_TITLE="${{ github.event.pull_request.title }}" + PR_LABELS="${{ toJSON(github.event.pull_request.labels.*.name) }}" + + # Check for bypass markers in PR title + if echo "$PR_TITLE" | grep -qE '\[EMERGENCY\]|\[SKIP REVIEW\]|\[HOTFIX\]'; then + echo "bypass=true" >> $GITHUB_OUTPUT + echo "reason=PR title contains bypass marker" >> $GITHUB_OUTPUT + echo "⏭️ BYPASS: PR title contains bypass marker" + exit 0 + fi + + # Check for bypass labels + if echo "$PR_LABELS" | grep -qE 'emergency|skip-review|hotfix'; then + echo "bypass=true" >> $GITHUB_OUTPUT + echo "reason=PR has bypass label" >> $GITHUB_OUTPUT + echo "⏭️ BYPASS: PR has bypass label" + exit 0 + fi + + echo "bypass=false" >> $GITHUB_OUTPUT + echo "✅ No bypass detected - review will proceed" + + - name: Post Bypass Notice + if: steps.bypass.outputs.bypass == 'true' + uses: actions/github-script@v7 + with: + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `## ⏭️ Code Review Bypassed + + **Reason**: ${{ steps.bypass.outputs.reason }} + + ⚠️ **Manual review recommended** - This PR was merged without automated code review. + + --- + *Bypass triggered by emergency procedures protocol*` + }) + - name: Checkout repository + if: steps.bypass.outputs.bypass != 'true' uses: actions/checkout@v4 with: fetch-depth: 1 - name: Run Claude Code Review + if: steps.bypass.outputs.bypass != 'true' id: claude-review uses: anthropics/claude-code-action@v1 + continue-on-error: true with: claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} prompt: | @@ -46,12 +99,33 @@ jobs: - Performance considerations - Security concerns - Test coverage + - Skill quality (if applicable) Use the repository's CLAUDE.md for guidance on style and conventions. Be constructive and helpful in your feedback. Use `gh pr comment` with your Bash tool to leave your review as a comment on the PR. # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md - # or https://docs.claude.com/en/docs/claude-code/cli-reference for available options - claude_args: '--allowed-tools "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*),Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)"' + # or https://docs.claude.com/en/docs/claude-code/cli-reference + claude_args: >- + --allowed-tools + "Bash(gh issue view:*),Bash(gh search:*),Bash(gh issue list:*), + Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(gh pr list:*)" + - name: Post fallback review note (quota/timeout) + if: steps.claude-review.outcome != 'success' + uses: actions/github-script@v7 + with: + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: `## ⚠️ Automated Review Skipped + + The automated Claude review could not complete (likely quota or a transient error). + + - You can retry this workflow from the Actions tab + - Proceed with manual review to unblock + ` + }) diff --git a/.github/workflows/pr-issue-auto-close.yml b/.github/workflows/pr-issue-auto-close.yml new file mode 100644 index 0000000..c9d72e0 --- /dev/null +++ b/.github/workflows/pr-issue-auto-close.yml @@ -0,0 +1,207 @@ +--- +name: Auto-Close Issues on PR Merge + +'on': + pull_request: + types: [closed] + +permissions: + issues: write + pull-requests: read + contents: read + +jobs: + close-linked-issues: + name: Close Issues Linked in PR + if: github.event.pull_request.merged == true + runs-on: ubuntu-latest + + steps: + - name: Check Workflow Kill Switch + run: | + if [ -f ".github/WORKFLOW_KILLSWITCH" ]; then + STATUS=$(grep "STATUS:" .github/WORKFLOW_KILLSWITCH | awk '{print $2}') + if [ "$STATUS" = "DISABLED" ]; then + echo "🛑 Workflows disabled by kill switch" + exit 0 + fi + fi + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Extract linked issues from PR body + id: extract_issues + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const prBody = context.payload.pull_request.body || ''; + const prNumber = context.payload.pull_request.number; + + // Patterns to detect linked issues + // Supports: Fixes #123, Closes #456, Resolves #789, Related to #111, See #222 + const patterns = [ + /(?:fix|fixes|fixed|close|closes|closed|resolve|resolves|resolved)\s+#(\d+)/gi, + /(?:related\s+to|see|ref|references)\s+#(\d+)/gi + ]; + + const issueNumbers = new Set(); + + // Extract issue numbers + patterns.forEach(pattern => { + let match; + while ((match = pattern.exec(prBody)) !== null) { + issueNumbers.add(match[1]); + } + }); + + // Also check PR title + const prTitle = context.payload.pull_request.title || ''; + patterns.forEach(pattern => { + let match; + while ((match = pattern.exec(prTitle)) !== null) { + issueNumbers.add(match[1]); + } + }); + + // Also check commit messages in PR + const commits = await github.rest.pulls.listCommits({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: prNumber + }); + + commits.data.forEach(commit => { + const message = commit.commit.message; + patterns.forEach(pattern => { + let match; + while ((match = pattern.exec(message)) !== null) { + issueNumbers.add(match[1]); + } + }); + }); + + const issues = Array.from(issueNumbers); + console.log(`Found linked issues: ${issues.join(', ')}`); + + return issues; + + - name: Close linked issues + if: steps.extract_issues.outputs.result != '[]' + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issueNumbers = ${{ steps.extract_issues.outputs.result }}; + const prNumber = context.payload.pull_request.number; + const prTitle = context.payload.pull_request.title; + const prUrl = context.payload.pull_request.html_url; + const merger = context.payload.pull_request.merged_by.login; + + console.log(`Processing ${issueNumbers.length} linked issue(s)`); + + for (const issueNumber of issueNumbers) { + try { + // Get issue details first + const issue = await github.rest.issues.get({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: parseInt(issueNumber) + }); + + // Skip if already closed + if (issue.data.state === 'closed') { + console.log(`Issue #${issueNumber} already closed, skipping`); + continue; + } + + // Add comment explaining closure + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: parseInt(issueNumber), + body: `## ✅ Completed via PR #${prNumber} + +**PR**: ${prTitle} +**URL**: ${prUrl} +**Merged by**: @${merger} + +This issue has been resolved and the changes have been merged into main. + +🤖 Automatically closed via PR merge automation` + }); + + // Close the issue + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: parseInt(issueNumber), + state: 'closed', + state_reason: 'completed' + }); + + console.log(`✅ Closed issue #${issueNumber}`); + + } catch (error) { + console.error(`❌ Failed to close issue #${issueNumber}: ${error.message}`); + } + } + + - name: Update project board status + if: steps.extract_issues.outputs.result != '[]' + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issueNumbers = ${{ steps.extract_issues.outputs.result }}; + + for (const issueNumber of issueNumbers) { + try { + // Add status: done label + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: parseInt(issueNumber), + labels: ['status: done'] + }); + + // Remove in-progress and in-review labels + const labelsToRemove = ['status: in-progress', 'status: in-review']; + for (const label of labelsToRemove) { + try { + await github.rest.issues.removeLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: parseInt(issueNumber), + name: label + }); + } catch (e) { + // Label might not exist, ignore error + } + } + + console.log(`✅ Updated project status for issue #${issueNumber}`); + + } catch (error) { + console.error(`❌ Failed to update status for issue #${issueNumber}: ${error.message}`); + } + } + + - name: Summary + if: steps.extract_issues.outputs.result != '[]' + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const issueNumbers = ${{ steps.extract_issues.outputs.result }}; + const prNumber = context.payload.pull_request.number; + + console.log(` + ✅ PR #${prNumber} Merge Automation Complete + + Closed issues: ${issueNumbers.join(', ')} + Updated project board: status → done + Comments added: Linked to PR #${prNumber} + + All linked issues have been automatically closed and marked as done. + `); diff --git a/.github/workflows/smart-sync.yml b/.github/workflows/smart-sync.yml new file mode 100644 index 0000000..090d00a --- /dev/null +++ b/.github/workflows/smart-sync.yml @@ -0,0 +1,442 @@ +--- +name: Smart Bidirectional Sync + +'on': + issues: + types: [labeled, closed, reopened] + projects_v2_item: + types: [edited] + +# Prevent sync loops with debouncing +concurrency: + group: smart-sync-${{ github.event.issue.number || github.event.projects_v2_item.node_id }} + cancel-in-progress: true # Cancel pending runs (debouncing effect) + +jobs: + determine-direction: + runs-on: ubuntu-latest + timeout-minutes: 3 + permissions: + contents: read + issues: read + id-token: write + + outputs: + should_sync: ${{ steps.check.outputs.should_sync }} + direction: ${{ steps.check.outputs.direction }} + issue_number: ${{ steps.check.outputs.issue_number }} + + steps: + - name: Check Workflow Kill Switch + run: | + if [ -f ".github/WORKFLOW_KILLSWITCH" ]; then + STATUS=$(grep "STATUS:" .github/WORKFLOW_KILLSWITCH | awk '{print $2}') + if [ "$STATUS" = "DISABLED" ]; then + echo "🛑 Workflows disabled by kill switch" + exit 0 + fi + fi + - name: Determine Sync Direction + id: check + run: | + # Check which event triggered this workflow + if [ "${{ github.event_name }}" = "issues" ]; then + # Issue event → sync to project board + echo "direction=issue-to-project" >> $GITHUB_OUTPUT + echo "issue_number=${{ github.event.issue.number }}" >> $GITHUB_OUTPUT + + # Only sync on status label changes or state changes + if [[ "${{ github.event.action }}" == "labeled" && "${{ github.event.label.name }}" == status:* ]] || \ + [ "${{ github.event.action }}" = "closed" ] || \ + [ "${{ github.event.action }}" = "reopened" ]; then + echo "should_sync=true" >> $GITHUB_OUTPUT + echo "✅ Will sync: Issue #${{ github.event.issue.number }} → Project Board" + else + echo "should_sync=false" >> $GITHUB_OUTPUT + echo "⏭️ Skipping: Not a status change or state change" + fi + + elif [ "${{ github.event_name }}" = "projects_v2_item" ]; then + # Project event → sync to issue + echo "direction=project-to-issue" >> $GITHUB_OUTPUT + echo "should_sync=true" >> $GITHUB_OUTPUT + echo "✅ Will sync: Project Board → Issue" + + else + echo "should_sync=false" >> $GITHUB_OUTPUT + echo "⚠️ Unknown event type" + fi + + rate-limit-check: + needs: determine-direction + if: needs.determine-direction.outputs.should_sync == 'true' + runs-on: ubuntu-latest + timeout-minutes: 2 + permissions: + contents: read + + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + outputs: + can_proceed: ${{ steps.limits.outputs.can_proceed }} + + steps: + - name: Check Rate Limits (Circuit Breaker) + id: limits + run: | + echo "🔍 Checking GitHub API rate limits..." + + # Get rate limit status + core_remaining=$(gh api rate_limit --jq '.resources.core.remaining') + core_limit=$(gh api rate_limit --jq '.resources.core.limit') + graphql_remaining=$(gh api rate_limit --jq '.resources.graphql.remaining') + graphql_limit=$(gh api rate_limit --jq '.resources.graphql.limit') + + echo "📊 Rate Limits:" + echo " REST API: $core_remaining/$core_limit" + echo " GraphQL: $graphql_remaining/$graphql_limit" + + # Require at least 50 remaining for sync operations + if [ "$core_remaining" -lt 50 ] || [ "$graphql_remaining" -lt 50 ]; then + echo "can_proceed=false" >> $GITHUB_OUTPUT + echo "⚠️ Rate limits too low. Skipping sync to prevent violations." + exit 0 + fi + + echo "can_proceed=true" >> $GITHUB_OUTPUT + echo "✅ Rate limits sufficient for sync operation" + + # 10-second debounce delay + debounce: + needs: [determine-direction, rate-limit-check] + if: | + needs.determine-direction.outputs.should_sync == 'true' && + needs.rate-limit-check.outputs.can_proceed == 'true' + runs-on: ubuntu-latest + timeout-minutes: 1 + + steps: + - name: Debounce Delay + run: | + echo "⏱️ Applying 10-second debounce..." + sleep 10 + echo "✅ Debounce complete. Proceeding with sync." + + sync-issue-to-project: + needs: [determine-direction, rate-limit-check, debounce] + if: | + needs.determine-direction.outputs.direction == 'issue-to-project' && + needs.rate-limit-check.outputs.can_proceed == 'true' + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: + contents: read + issues: read + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Sync Issue to Project Board + uses: anthropics/claude-code-action@v1 + env: + GH_TOKEN: ${{ secrets.PROJECTS_TOKEN }} + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + + prompt: | + # Issue → Project Board Sync + + **Issue**: #${{ github.event.issue.number }} "${{ github.event.issue.title }}" + **State**: ${{ github.event.issue.state }} + **Action**: ${{ github.event.action }} + + ## Task: Sync issue status to project board + + ### Step 1: Check if in Project + ```bash + PROJECT_ITEM=$(gh api graphql -f query=' + query { + repository(owner: "alirezarezvani", name: "claude-skills") { + issue(number: ${{ github.event.issue.number }}) { + projectItems(first: 10) { + nodes { + id + project { number } + } + } + } + } + } + ' --jq '.data.repository.issue.projectItems.nodes[] | select(.project.number == 9) | .id') + + if [ -z "$PROJECT_ITEM" ]; then + echo "Adding to project..." + gh project item-add 9 --owner alirezarezvani --url ${{ github.event.issue.html_url }} + sleep 2 + + PROJECT_ITEM=$(gh api graphql -f query=' + query { + repository(owner: "alirezarezvani", name: "claude-skills") { + issue(number: ${{ github.event.issue.number }}) { + projectItems(first: 10) { + nodes { + id + project { number } + } + } + } + } + } + ' --jq '.data.repository.issue.projectItems.nodes[] | select(.project.number == 9) | .id') + fi + + echo "Project Item ID: $PROJECT_ITEM" + ``` + + ### Step 2: Determine Target Status + ```bash + LABELS=$(gh issue view ${{ github.event.issue.number }} --json labels --jq '[.labels[].name] | join(",")') + ISSUE_STATE="${{ github.event.issue.state }}" + + # Priority order: closed state > status labels > default + if [ "$ISSUE_STATE" = "closed" ]; then + TARGET_STATUS="Done" + elif echo "$LABELS" | grep -q "status: done"; then + TARGET_STATUS="Done" + elif echo "$LABELS" | grep -q "status: in-review"; then + TARGET_STATUS="In Review" + elif echo "$LABELS" | grep -q "status: in-progress"; then + TARGET_STATUS="In Progress" + elif echo "$LABELS" | grep -q "status: ready"; then + TARGET_STATUS="Ready" + elif echo "$LABELS" | grep -q "status: backlog"; then + TARGET_STATUS="Backlog" + elif echo "$LABELS" | grep -q "status: triage"; then + TARGET_STATUS="To triage" + else + TARGET_STATUS=$([ "$ISSUE_STATE" = "open" ] && echo "To triage" || echo "Done") + fi + + echo "Target Status: $TARGET_STATUS" + ``` + + ### Step 3: Get Project IDs + ```bash + PROJECT_DATA=$(gh api graphql -f query=' + query { + user(login: "alirezarezvani") { + projectV2(number: 9) { + id + fields(first: 20) { + nodes { + ... on ProjectV2SingleSelectField { + id + name + options { + id + name + } + } + } + } + } + } + } + ') + + PROJECT_ID=$(echo "$PROJECT_DATA" | jq -r '.data.user.projectV2.id') + STATUS_FIELD_ID=$(echo "$PROJECT_DATA" | \ + jq -r '.data.user.projectV2.fields.nodes[] | select(.name == "Status") | .id') + STATUS_OPTION_ID=$(echo "$PROJECT_DATA" | jq -r --arg status "$TARGET_STATUS" \ + '.data.user.projectV2.fields.nodes[] | select(.name == "Status") | .options[] | select(.name == $status) | .id') + ``` + + ### Step 4: Update Project Board + ```bash + if [ -n "$PROJECT_ITEM" ] && [ -n "$STATUS_OPTION_ID" ]; then + gh api graphql -f query=' + mutation { + updateProjectV2ItemFieldValue( + input: { + projectId: "'"$PROJECT_ID"'" + itemId: "'"$PROJECT_ITEM"'" + fieldId: "'"$STATUS_FIELD_ID"'" + value: { singleSelectOptionId: "'"$STATUS_OPTION_ID"'" } + } + ) { + projectV2Item { id } + } + } + ' + echo "✅ Project board updated to: $TARGET_STATUS" + else + echo "⚠️ Could not update (missing IDs)" + fi + ``` + + ## Rules + - DO NOT comment on issue (prevents notification spam) + - DO NOT modify issue labels (prevents sync loop) + - Only update project board status + + claude_args: '--allowed-tools "Bash(gh issue:*),Bash(gh api:*),Bash(gh project:*),Bash(echo:*),Bash(sleep:*)"' + + sync-project-to-issue: + needs: [determine-direction, rate-limit-check, debounce] + if: | + needs.determine-direction.outputs.direction == 'project-to-issue' && + needs.rate-limit-check.outputs.can_proceed == 'true' + runs-on: ubuntu-latest + timeout-minutes: 5 + permissions: + contents: read + issues: write + id-token: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Sync Project Board to Issue + uses: anthropics/claude-code-action@v1 + env: + GH_TOKEN: ${{ secrets.PROJECTS_TOKEN }} + with: + claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }} + + prompt: | + # Project Board → Issue Sync + + **Project Item**: ${{ github.event.projects_v2_item.node_id }} + **Content**: ${{ github.event.projects_v2_item.content_node_id }} + **Changed By**: @${{ github.event.sender.login }} + + ## Task: Sync project board status to issue + + ### Step 1: Get Issue Number + ```bash + CONTENT_ID="${{ github.event.projects_v2_item.content_node_id }}" + + ISSUE_DATA=$(gh api graphql -f query=' + query { + node(id: "${{ github.event.projects_v2_item.node_id }}") { + ... on ProjectV2Item { + content { + ... on Issue { + number + url + state + title + } + } + } + } + } + ') + + ISSUE_NUMBER=$(echo "$ISSUE_DATA" | jq -r '.data.node.content.number') + + if [ -z "$ISSUE_NUMBER" ] || [ "$ISSUE_NUMBER" = "null" ]; then + echo "⏭️ Not an issue (might be PR or other content)" + exit 0 + fi + + echo "Issue Number: $ISSUE_NUMBER" + ``` + + ### Step 2: Get Project Status + ```bash + STATUS=$(gh api graphql -f query=' + query { + node(id: "${{ github.event.projects_v2_item.node_id }}") { + ... on ProjectV2Item { + fieldValues(first: 20) { + nodes { + ... on ProjectV2ItemFieldSingleSelectValue { + name + field { + ... on ProjectV2SingleSelectField { + name + } + } + } + } + } + } + } + } + ' --jq '.data.node.fieldValues.nodes[] | select(.field.name == "Status") | .name') + + if [ -z "$STATUS" ]; then + echo "⏭️ No status field found" + exit 0 + fi + + echo "Project Status: $STATUS" + ``` + + ### Step 3: Map Status to Label + ```bash + case "$STATUS" in + "To triage") NEW_LABEL="status: triage" ;; + "Backlog") NEW_LABEL="status: backlog" ;; + "Ready") NEW_LABEL="status: ready" ;; + "In Progress") NEW_LABEL="status: in-progress" ;; + "In Review") NEW_LABEL="status: in-review" ;; + "Done") NEW_LABEL="status: done" ;; + *) + echo "⏭️ Unknown status: $STATUS" + exit 0 + ;; + esac + + echo "Target Label: $NEW_LABEL" + ``` + + ### Step 4: Update Issue Labels + ```bash + CURRENT_LABELS=$(gh issue view $ISSUE_NUMBER --json labels --jq '[.labels[].name] | join(",")') + + # Remove all status: labels + for label in "status: triage" "status: backlog" "status: ready" "status: in-progress" "status: in-review" "status: done"; do + if echo "$CURRENT_LABELS" | grep -q "$label"; then + gh issue edit $ISSUE_NUMBER --remove-label "$label" 2>/dev/null || true + fi + done + + # Add new status label + gh issue edit $ISSUE_NUMBER --add-label "$NEW_LABEL" + echo "✅ Label updated to: $NEW_LABEL" + ``` + + ### Step 5: Handle Issue State + ```bash + CURRENT_STATE=$(gh issue view $ISSUE_NUMBER --json state --jq '.state') + + if [ "$STATUS" = "Done" ] && [ "$CURRENT_STATE" = "OPEN" ]; then + gh issue close $ISSUE_NUMBER --reason completed + echo "✅ Issue closed (moved to Done)" + elif [ "$STATUS" != "Done" ] && [ "$CURRENT_STATE" = "CLOSED" ]; then + gh issue reopen $ISSUE_NUMBER + echo "✅ Issue reopened (moved from Done)" + fi + ``` + + ### Step 6: Silent Completion + ```bash + echo "✅ Sync complete: Issue #$ISSUE_NUMBER updated to $STATUS" + ``` + + ## Rules + - DO NOT comment on issue (prevents notification spam) + - DO NOT modify project board (prevents sync loop) + - Only update issue labels and state + + claude_args: '--allowed-tools "Bash(gh issue:*),Bash(gh api:*),Bash(echo:*)"'