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
97 changes: 97 additions & 0 deletions .github/workflows/ci-failure-auto-fix.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
name: Auto Fix CI Failures

on:
workflow_run:
workflows: ["CI"]
types:
- completed

permissions:
contents: write
pull-requests: write
actions: read
issues: write
id-token: write # Required for OIDC token exchange

jobs:
auto-fix:
if: |
github.event.workflow_run.conclusion == 'failure' &&
github.event.workflow_run.pull_requests[0] &&
!startsWith(github.event.workflow_run.head_branch, 'claude-auto-fix-ci-')
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
ref: ${{ github.event.workflow_run.head_branch }}
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}

- name: Setup git identity
run: |
git config --global user.email "claude[bot]@users.noreply.github.com"
git config --global user.name "claude[bot]"

- name: Create fix branch
id: branch
run: |
BRANCH_NAME="claude-auto-fix-ci-${{ github.event.workflow_run.head_branch }}-${{ github.run_id }}"
git checkout -b "$BRANCH_NAME"
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT

- name: Get CI failure details
id: failure_details
uses: actions/github-script@v7
with:
script: |
const run = await github.rest.actions.getWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }}
});

const jobs = await github.rest.actions.listJobsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }}
});

const failedJobs = jobs.data.jobs.filter(job => job.conclusion === 'failure');

let errorLogs = [];
for (const job of failedJobs) {
const logs = await github.rest.actions.downloadJobLogsForWorkflowRun({
owner: context.repo.owner,
repo: context.repo.repo,
job_id: job.id
});
errorLogs.push({
jobName: job.name,
logs: logs.data
});
}

return {
runUrl: run.data.html_url,
failedJobs: failedJobs.map(j => j.name),
errorLogs: errorLogs
};

- name: Fix CI failures with Claude
id: claude
uses: anthropics/claude-code-action@v1
with:
prompt: |
/fix-ci
Failed CI Run: ${{ fromJSON(steps.failure_details.outputs.result).runUrl }}
Failed Jobs: ${{ join(fromJSON(steps.failure_details.outputs.result).failedJobs, ', ') }}
PR Number: ${{ github.event.workflow_run.pull_requests[0].number }}
Branch Name: ${{ steps.branch.outputs.branch_name }}
Base Branch: ${{ github.event.workflow_run.head_branch }}
Repository: ${{ github.repository }}

Error logs:
${{ toJSON(fromJSON(steps.failure_details.outputs.result).errorLogs) }}
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
claude_args: "--allowedTools 'Edit,MultiEdit,Write,Read,Glob,Grep,LS,Bash(git:*),Bash(bun:*),Bash(npm:*),Bash(npx:*),Bash(gh:*)'"
58 changes: 58 additions & 0 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Claude Code

on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]

jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
issues: write
id-token: write
actions: read # Required for Claude to read CI results on PRs
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 1

- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@v1
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}

# Optional: Customize the trigger phrase (default: @claude)
# trigger_phrase: "/claude"

# Optional: Trigger when specific user is assigned to an issue
# assignee_trigger: "claude-bot"

# Optional: Configure Claude's behavior with CLI arguments
# claude_args: |
# --model claude-opus-4-1-20250805
# --max-turns 10
# --allowedTools "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)"
# --system-prompt "Follow our coding standards. Ensure all new code has tests. Use TypeScript for new files."

# Optional: Advanced settings configuration
# settings: |
# {
# "env": {
# "NODE_ENV": "test"
# }
# }
59 changes: 59 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# CLAUDE.md

## Code Style

- C++11 unless otherwise specified
- Boost C++ Libraries naming conventions (snake_case)
- 4-space indentation, no tabs
- Braces on their own line for classes/functions

## Javadoc Documentation

Follow Boost C++ Libraries Javadoc style:

- Brief descriptions on first line after `/**`
- Functions returning values: brief starts with "Return"
- Use `@param` for function parameters
- Use `@tparam` for template parameters, except:
- Variadic args (`Args...`) — omit
- Types deduced from function parameters — omit (self-evident from `@param`)
- Use `@return` for return value details
- Use `@pre` for preconditions
- Use `@post` for postconditions
- Use `@throws` for exceptions
- Use `@note` for important notes
- Use `@see` for cross-references
- Use `@code` / `@endcode` for examples

## Examples

```cpp
/** Return the size of the buffer sequence.

@param buffers The buffer sequence to measure.

@return The total byte count.
*/
template<class BufferSequence>
std::size_t
buffer_size(BufferSequence const& buffers);
```

No `@tparam` needed—`BufferSequence` is evident from `@param buffers`.

```cpp
/** Return the default value.

@tparam T The value type.
*/
template<class T>
T default_value();
```

`@tparam` needed—`T` has no corresponding function parameter.

## Preferences

- Concise, dry answers
- Full files, not diffs
- Accurate, compiling C++ code
Loading