Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions .github/workflows/content-policy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: Content Policy

on:
pull_request:
types: [opened, edited, reopened]
issues:
types: [opened, edited, reopened]
issue_comment:
types: [created, edited]

permissions:
contents: read
pull-requests: read
issues: read

jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Check content policy
uses: actions/github-script@v7
with:
script: |
const FORBIDDEN_EMOJIS = ['🤖', '✅', '❌', '🚀', '🚫', '✨', '❤️'];

// Get the content to check based on event type
let content = '';
let contentType = '';

if (context.eventName === 'pull_request') {
content = context.payload.pull_request.body || '';
contentType = 'PR description';
} else if (context.eventName === 'issues') {
content = context.payload.issue.body || '';
contentType = 'Issue description';
} else if (context.eventName === 'issue_comment') {
content = context.payload.comment.body || '';
contentType = 'Comment';
}

const errors = [];

// Check for forbidden emojis
for (const emoji of FORBIDDEN_EMOJIS) {
if (content.includes(emoji)) {
errors.push(`Contains forbidden emoji: ${emoji}`);
}
}

// Check for redundant Claude attributions (use full email to avoid false positives)
const hasCoAuthored = content.includes('Co-Authored-By: Claude <noreply@anthropic.com>');
const hasGeneratedWith = content.includes('Generated with [Claude Code]');

if (hasCoAuthored && hasGeneratedWith) {
errors.push('Contains both "Co-Authored-By: Claude" and "Generated with [Claude Code]" - use one or the other, not both');
}

if (errors.length > 0) {
let message = `## Content Policy Violation\n\n${contentType} contains the following issues:\n\n${errors.map(e => `- ${e}`).join('\n')}\n\n`;

// Add recommendation for redundant Claude attributions
if (hasCoAuthored && hasGeneratedWith) {
message += `**Recommended signature for Claude Code contributions:**\n\n> Generated with [Claude Code](https://claude.com/claude-code)\n> Steered and verified by @your-username\n\n`;
}

message += 'Please edit to fix these issues.';
core.setFailed(message);
}
44 changes: 44 additions & 0 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/usr/bin/env sh
set -e
# commit-msg hook: Reject forbidden emojis in commit messages
#
# This is a global hook (committed to repo) that applies to all contributors.
# Rejects commits containing unprofessional emojis commonly added by AI tools.
#
# To bypass this check temporarily (for emergencies):
# git commit --no-verify

commit_msg_file=$1

# Extract just the commit message (before any diff/patch content)
# This prevents false positives when commits remove emojis from code
commit_msg=$(sed '/^---$/q;/^diff /q' "$commit_msg_file" | sed '$d')

# Forbidden emojis (commonly added by AI tools)
FORBIDDEN_EMOJIS="🤖 ✅ ❌ 🚀 🚫 ✨ ❤️"

detected=""
for emoji in $FORBIDDEN_EMOJIS; do
if printf '%s' "$commit_msg" | grep -q "$emoji"; then
detected="$emoji"
break
fi
done

if [ -n "$detected" ]; then
echo ""
echo "COMMIT REJECTED"
echo ""
echo "Commit message contains forbidden emoji: $detected"
echo "Please remove emojis from your commit message."
echo ""
echo "To bypass (emergencies only): git commit --no-verify"
echo ""
exit 1
fi

# Call local hook if it exists (for personal/machine-specific rules)
GIT_COMMON_DIR=$(git rev-parse --git-common-dir)
if [ -x "$GIT_COMMON_DIR/hooks/commit-msg" ]; then
"$GIT_COMMON_DIR/hooks/commit-msg" "$@" || exit $?
fi