Skip to content
Open
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
34 changes: 34 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
version: 2

# Grouped so a week's updates arrive as one reviewable change per ecosystem
# rather than one per dependency. The packages under `packages/` share a lock
# discipline, so pip updates are grouped across the repository.
updates:
- package-ecosystem: pip
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 3
groups:
# Torch decides what the engine can run and how large every artifact
# is, so it lands on its own rather than inside a bulk update.
torch:
patterns:
- torch
- torchvision
python:
patterns:
- "*"
exclude-patterns:
- torch
- torchvision

- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
open-pull-requests-limit: 3
groups:
actions:
patterns:
- "*"
134 changes: 134 additions & 0 deletions .github/workflows/agent-issue.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
name: Work an issue

# Turns a labelled issue into a pull request without a person opening a
# session. Label an issue `agent`, or comment `/agent`, and the work starts.
#
# The model is reached through aider, which speaks to any OpenAI-compatible
# endpoint, so the provider is configuration rather than code:
#
# secret LLM_API_KEY the provider key
# secret AUTOMATION_TOKEN a PAT or App token
# variable LLM_BASE_URL e.g. https://openrouter.ai/api/v1
# variable LLM_MODEL the provider's exact model slug
#
# `AUTOMATION_TOKEN` is not optional. GitHub does not start workflow runs for
# events raised by the built-in `GITHUB_TOKEN`, so a pull request opened with
# it sits with no checks and can never satisfy auto-merge.
#
# The agent cannot merge, cannot approve, and cannot push to main: `main`
# requires a pull request and its checks. That is the whole reason it is
# reasonable to let a model write here unattended.

on:
issues:
types: [labeled]
issue_comment:
types: [created]

permissions:
contents: read
issues: write

jobs:
work:
# `issue_comment` fires for pull requests too; `.issue.pull_request` is
# absent on a real issue, which is how the two are told apart.
if: >
(github.event_name == 'issues' &&
github.event.label.name == 'agent') ||
(github.event_name == 'issue_comment' &&
!github.event.issue.pull_request &&
startsWith(github.event.comment.body, '/agent'))
runs-on: [self-hosted, linux, x64, spikeforge-ci]
timeout-minutes: 60
steps:
- name: Check the configuration exists
shell: bash
run: |
missing=""
[ -z "${{ secrets.LLM_API_KEY }}" ] && missing="$missing LLM_API_KEY"
[ -z "${{ secrets.AUTOMATION_TOKEN }}" ] && missing="$missing AUTOMATION_TOKEN"
[ -z "${{ vars.LLM_BASE_URL }}" ] && missing="$missing LLM_BASE_URL"
[ -z "${{ vars.LLM_MODEL }}" ] && missing="$missing LLM_MODEL"
if [ -n "$missing" ]; then
echo "::error::missing configuration:$missing"
exit 1
fi

- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.AUTOMATION_TOKEN }}

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install the agent
run: python -m pip install --upgrade aider-chat

- name: Write the instructions
shell: bash
env:
ISSUE_TITLE: ${{ github.event.issue.title }}
ISSUE_BODY: ${{ github.event.issue.body }}
run: |
# Through a file, not an argument: an issue body is arbitrary text
# and interpolating it into a shell command would let its contents
# decide what runs.
{
echo "Work this issue."
echo
echo "Title: $ISSUE_TITLE"
echo
echo "$ISSUE_BODY"
echo
echo "Read this repository's own guidance first -- rules.md, and"
echo "AGENTS.md or CLAUDE.md if present. It is binding."
echo
echo "Five published distributions and two applications build"
echo "against this repository. If you change a version, update"
echo "compatibility.json to match: the dashboard pins both its"
echo "end-to-end suite and the engine inside the desktop"
echo "application to that file, so leaving it behind ships a"
echo "mismatched build."
} > /tmp/agent-instructions.txt
cat /tmp/agent-instructions.txt

- name: Make the change
env:
OPENAI_API_KEY: ${{ secrets.LLM_API_KEY }}
OPENAI_API_BASE: ${{ vars.LLM_BASE_URL }}
run: |
set -euo pipefail
branch="agent/issue-${{ github.event.issue.number }}"
git config user.name "spikeforge-agent"
git config user.email "contact@capsizegames.com"
git checkout -b "$branch"
aider --yes --no-analytics --no-gitignore \
--model "openai/${{ vars.LLM_MODEL }}" \
--message-file /tmp/agent-instructions.txt
if git diff --quiet HEAD; then
echo "::error::the agent produced no change"
exit 1
fi

- name: Check its work
run: |
python -m pip install -e ".[dev]" || python -m pip install -e .
python -m pytest -x -q

- name: Open the pull request
env:
GH_TOKEN: ${{ secrets.AUTOMATION_TOKEN }}
run: |
set -euo pipefail
branch="agent/issue-${{ github.event.issue.number }}"
git push --set-upstream origin "$branch"
gh pr create --base main --head "$branch" \
--title "${{ github.event.issue.title }}" \
--body "Closes #${{ github.event.issue.number }}.

Written by \`${{ vars.LLM_MODEL }}\` from the issue text. Nobody has
read this. The test suite passed on the runner before it was opened;
the required checks decide whether it merges."
59 changes: 59 additions & 0 deletions .github/workflows/agent-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Review a pull request

# Reviews every pull request. With nobody reading the diff, this is the only
# thing that looks at a change as a change rather than as a test result.
#
# It talks to any OpenAI-compatible chat-completions endpoint -- OpenRouter,
# DeepInfra, or anything else speaking that protocol -- so the provider and
# model are configuration, not code:
#
# secret LLM_API_KEY the provider key
# variable LLM_BASE_URL e.g. https://openrouter.ai/api/v1
# variable LLM_MODEL the provider's exact model slug
#
# It posts a comment. It cannot approve, block, or merge: the required checks
# decide that.

on:
pull_request:
types: [opened, synchronize, reopened]

permissions:
contents: read
pull-requests: write

jobs:
review:
if: ${{ !github.event.pull_request.draft }}
runs-on: [self-hosted, linux, x64, spikeforge-ci]
timeout-minutes: 20
steps:
- name: Skip without a provider
id: guard
shell: bash
run: |
if [ -z "${{ secrets.LLM_API_KEY }}" ] \
|| [ -z "${{ vars.LLM_BASE_URL }}" ] \
|| [ -z "${{ vars.LLM_MODEL }}" ]; then
echo "LLM_API_KEY, LLM_BASE_URL or LLM_MODEL is unset;"
echo "no review will be posted."
echo "skip=true" >> "$GITHUB_OUTPUT"
fi

- uses: actions/checkout@v4
if: steps.guard.outputs.skip != 'true'

- uses: actions/setup-node@v4
if: steps.guard.outputs.skip != 'true'
with:
node-version: "22"

- name: Post the review
if: steps.guard.outputs.skip != 'true'
env:
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_BASE_URL: ${{ vars.LLM_BASE_URL }}
LLM_MODEL: ${{ vars.LLM_MODEL }}
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: node scripts/llm_review.mjs
16 changes: 7 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,16 @@ jobs:
steps:
- uses: actions/checkout@v4

# No `cache: pip` anywhere in this file. This fleet's runners keep
# `_work` on another drive behind a symlink, and setup-python's
# dependency-file glob does not see through it: it reports that no
# pyproject.toml exists and fails the job before anything is built,
# while all seven of them sit in `packages/`. A self-hosted runner also
# keeps `~/.cache/pip` between jobs on its own, so the action's cache
# was buying nothing here even when it worked.
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip

- name: Install the core dev extra
run: |
Expand Down Expand Up @@ -56,7 +62,6 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip

- name: Install torch CPU wheels
run: |
Expand Down Expand Up @@ -89,7 +94,6 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip

- name: Install torch CPU wheels
run: |
Expand Down Expand Up @@ -141,7 +145,6 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip

- name: Install torch CPU wheels
run: |
Expand Down Expand Up @@ -182,7 +185,6 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip

- name: Install torch CPU wheels
run: |
Expand Down Expand Up @@ -243,7 +245,6 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip

- name: Install torch CPU wheels
run: |
Expand Down Expand Up @@ -310,7 +311,6 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip

- name: Install docs dependencies
run: |
Expand All @@ -337,7 +337,6 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip

- name: Install the renderer PyPI itself uses
run: |
Expand Down Expand Up @@ -405,7 +404,6 @@ jobs:
- uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip

- name: Build the core wheel with no extras
run: |
Expand Down
Loading
Loading