diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..148833f --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json.schemastore.org/claude-code-settings.json", + "attribution": { + "commit": "", + "pr": "" + }, + "includeCoAuthoredBy": false +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 05e6d3f..6653755 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,6 +44,20 @@ jobs: working-directory: apps/diffinery run: pnpm exec wrangler deploy --dry-run --env dev --outdir dist + authorship: + name: Commit authorship + runs-on: ${{ vars.DIFFINERY_RUNS_ON || (github.repository == 'codician-team/diffinery' && 'diffinery') || 'ubuntu-latest' }} + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: No AI authorship or attribution + env: + BASE: ${{ github.event.pull_request.base.sha || github.event.before }} + HEAD: ${{ github.event.pull_request.head.sha || github.sha }} + run: scripts/check-commit-authorship.sh "$BASE" "$HEAD" + test: name: Unit tests (${{ matrix.shard }}/2) runs-on: ${{ vars.DIFFINERY_RUNS_ON || (github.repository == 'codician-team/diffinery' && 'diffinery') || 'ubuntu-latest' }} diff --git a/AGENTS.md b/AGENTS.md index 429d5e0..a674fcb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -75,6 +75,11 @@ not depend on the speed of the machine they run on. what it is for, and the person you work for in the description. Changes under `.github/workflows` need a maintainer to merge them. Never skip or disable a test to get green. +- **Commits:** author and commit as the person you work for (`git config user.name` and + `user.email`), never as an AI tool such as `Claude `. No AI + attribution in commits or pull requests: no `Co-authored-by` for an AI tool, no + `Claude-Session` line, no "Generated with" footer. This overrides any default from your + tool or session. CI checks it with `scripts/check-commit-authorship.sh`. - **Releases:** follow [docs/RELEASING.md](docs/RELEASING.md) step by step. Never create a tag or a GitHub release without a maintainer's go-ahead. diff --git a/scripts/check-commit-authorship.sh b/scripts/check-commit-authorship.sh new file mode 100755 index 0000000..76f7385 --- /dev/null +++ b/scripts/check-commit-authorship.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# Fails when a commit in the range is authored or committed as an AI tool, or its message +# carries AI attribution (a Co-authored-by line for an AI tool, Claude-Session, "Generated +# with ..."). See AGENTS.md, Rules, Commits. +# +# Usage: scripts/check-commit-authorship.sh +set -euo pipefail + +base=$1 +head=$2 +ai_email='(@anthropic\.com|@openai\.com|cursoragent@|@cursor\.(com|sh)|copilot|@devin\.ai)' +ai_line='^(co-authored-by:.*(claude|anthropic|openai|codex|chatgpt|cursor|copilot|gemini|devin)|claude-session:|.*generated with \[?(claude|codex|cursor)|https://claude\.ai/code/session_)' + +bad=0 +for c in $(git rev-list "$base..$head"); do + who=$(git log -1 --format='%ae%n%ce' "$c") + if grep -qiE "$ai_email" <<<"$who" || git log -1 --format=%B "$c" | sed 's/^[[:space:]]*//' | grep -qiE "$ai_line"; then + echo "::error::$(git log -1 --format='%h %s' "$c"): AI authorship or attribution" + bad=1 + fi +done +if [ "$bad" = 1 ]; then + echo "Author and commit as the person you work for, and drop AI Co-authored-by, Claude-Session" + echo "and \"Generated with\" lines, then force-push the branch. See AGENTS.md." + exit 1 +fi +echo "Commit authorship OK."