Dependency upkeep

A scheduled maintenance loop in the spirit of Dependabot. Every night, one agent finds outdated or vulnerable dependencies and opens a single pull request that bumps them.

The steps

1 step in workflows/dep-upkeep/. Triggered by the clock, it edits the checkout and pushes a branch.

bump.md
---
on: cron("0 3 * * *")
agent: Upkeeper
output: { pr_url: url, packages: int }
emits: DepsBumped
---
A checkout is in your workspace, with a GitHub token wired into git
and the `gh` CLI, so `git push` and PR creation just work.

Open one PR that brings dependencies up to date:

1. Detect the manifests (package.json, pyproject.toml, go.mod, ...).
2. Bump outdated packages to latest compatible versions; flag
   major-version bumps for a human rather than forcing them.
3. Branch, commit, push, and open a PR listing old and new versions.

If nothing is outdated, open no PR. Return the URL and count.

The trigger

A built-in cron("0 3 * * *") schedule (nightly at 3am), so there is no sensor to write. The tick carries {{ event.scheduled_at }}, which the step uses to name a unique branch per run.

The token

This workflow writes, so it needs git write access. loopy auth github configures a GitHub App and the backend injects a short-lived, repo-scoped token per step; or put a GITHUB_TOKEN with contents:write + pull_requests:write in the sandbox's env file.

From the registry

Only the outbound DepsBumped event needs declaring.

registry.yml
defaults:
  agent: { sandbox: BaseSandbox, model: claude-sonnet-4-6, harness: claude-code }

sandboxes:
  BaseSandbox:
    provider: daytona
    image: { debian_slim: "3.12", apt: [git, gh], workdir: /home/loopy, user: loopy }
    repos: [octocat/Hello-World]

agents:
  Upkeeper: {}  # finds outdated deps and opens the bump PR

events:  # outbound only; the cron(...) trigger is built in
  DepsBumped:
    pr_url: url
    packages: int
open on github → back to overview