Skip to content

Built-in dependency update workflow step #383

@marccampbell

Description

@marccampbell

Built-in dependency update workflow step

Goal

Elasticclaw should provide a built-in workflow step that discovers dependency manifests, updates supported dependencies using ecosystem-native tooling, produces structured output, and leaves the repository ready for later workflow steps to test, fix, and open a PR.

This step should be reusable from any workflow trigger:

  • Cron workflows, such as weekly dependency maintenance
  • Manual workflows, such as "run dependency updates now"
  • Future event-triggered workflows, such as security alerts

Cron scheduling is covered separately in #245. This issue is specifically about the dependency update capability inside a workflow.

Product shape

Example workflow usage:

name: dependency-updates

on:
  cron:
    schedule: "0 9 * * 1"
    timezone: "America/Chicago"

steps:
  - uses: elasticclaw/dependency-updates
    with:
      ecosystems:
        - go
        - npm
      grouping: all
      include_major: false
      separate_major: true
      separate_security: true
      separate_runtime: true

  - run: make test

  - uses: elasticclaw/open-pr
    with:
      title: "Update dependencies"
      branch_prefix: "elasticclaw/dependency-updates"

The dependency update step should not open the PR by itself. It should update files and emit structured metadata. Later workflow steps decide how to test, fix failures, commit, and open a PR.

Supported ecosystems

Start with a narrow, useful first version:

  • Go modules: go.mod, go.sum
  • Node/npm: package.json, package-lock.json

Later versions can add:

  • pnpm
  • Yarn
  • Ruby/Bundler
  • Python requirements files
  • Poetry
  • uv
  • Cargo
  • Maven/Gradle

The step should be designed so each ecosystem implementation is isolated and testable.

Behavior

The step should:

  • Discover supported manifests in the repository
  • Determine the package manager and lockfile type for each manifest
  • Identify available dependency updates
  • Classify updates where possible:
    • patch
    • minor
    • major
    • runtime/toolchain
    • security-related
  • Apply selected updates according to policy
  • Leave modified manifests and lockfiles in the working tree
  • Emit structured output for later steps and for the workflow run summary
  • Record skipped updates and the reason they were skipped

The step should prefer ecosystem-native tooling over custom version editing.

Examples:

  • Go: use go list, go get, go mod tidy, and related Go tooling
  • npm: use npm outdated, npm update, npm install, or other npm-native behavior

Configuration

Suggested options:

ecosystems:
  - go
  - npm

paths:
  - "."

grouping: all
include_major: false
separate_major: true
separate_security: true
separate_runtime: true

allow:
  - "*"

ignore:
  - "example-package"

commit_message: "Update dependencies"

Defaults:

ecosystems: auto
paths:
  - "."
grouping: all
include_major: false
separate_major: true
separate_security: true
separate_runtime: true
allow:
  - "*"
ignore: []

PR grouping model

The default grouping should be one update set per repository per workflow run for normal patch and minor updates.

That keeps scheduled dependency maintenance quiet and useful.

The model should still support splitting updates when appropriate:

  • Major updates can be skipped or emitted as a separate update group
  • Security updates can be emitted separately
  • Runtime/toolchain updates can be emitted separately
  • Failed grouped updates can be split by ecosystem or dependency in a later workflow step

Suggested grouping values:

grouping: all | ecosystem | dependency

The dependency update step does not need to create every PR shape itself. It should produce enough structured metadata for an open-pr step or an agent instruction to create the right PR.

Structured output

The step should emit machine-readable output similar to:

{
  "ecosystems": ["go", "npm"],
  "manifests": [
    {
      "ecosystem": "go",
      "path": "go.mod",
      "lockfiles": ["go.sum"]
    },
    {
      "ecosystem": "npm",
      "path": "web/package.json",
      "lockfiles": ["web/package-lock.json"]
    }
  ],
  "updates": [
    {
      "ecosystem": "go",
      "name": "github.com/example/module",
      "from": "v1.2.3",
      "to": "v1.3.0",
      "type": "minor",
      "applied": true,
      "group": "default"
    },
    {
      "ecosystem": "npm",
      "name": "example-package",
      "from": "2.4.0",
      "to": "3.0.0",
      "type": "major",
      "applied": false,
      "skipped_reason": "major updates disabled"
    }
  ],
  "commands": [
    {
      "command": "go get -u ./...",
      "exit_code": 0
    },
    {
      "command": "go mod tidy",
      "exit_code": 0
    }
  ],
  "files_changed": [
    "go.mod",
    "go.sum",
    "web/package.json",
    "web/package-lock.json"
  ]
}

This output should be available to:

  • Later workflow steps
  • The claw prompt/context
  • The workflow run summary
  • PR body generation

Failure behavior

The step should fail when dependency tooling fails in a way that prevents a reliable update.

Examples:

  • Package manager is missing
  • Lockfile update fails
  • Manifest is malformed
  • Registry request fails
  • Native tooling exits non-zero

When possible, the step should preserve useful partial metadata:

  • What manifests were discovered
  • What command failed
  • Exit code
  • Relevant stderr summary
  • Whether files were modified before failure

The workflow can then decide whether the claw should fix the issue, retry, split the update group, or stop.

Agent responsibilities

The built-in step should handle deterministic dependency mechanics.

The agent should handle judgment and repair work:

  • Decide whether a failed update can be fixed
  • Inspect changelogs or migration notes when needed
  • Update code for breaking changes
  • Split a failed grouped update into smaller attempts
  • Write a useful PR summary
  • Decide whether to skip an update with a clear reason

This keeps the updater predictable while still letting Elasticclaw use agent reasoning where it adds value.

Non-goals

  • Do not make this cron-only
  • Do not open PRs inside the dependency update step
  • Do not hand-edit manifest versions when ecosystem tooling can do it correctly
  • Do not support every package manager in the first version
  • Do not create one PR per dependency by default
  • Do not silently ignore failed package manager commands

First shippable version

Implement:

  • Workflow step definition: elasticclaw/dependency-updates
  • Auto-discovery for Go and npm
  • Basic config for ecosystems, paths, include_major, and grouping
  • Default grouped patch/minor updates
  • Major updates skipped by default
  • Go module updates using Go tooling
  • npm updates using npm tooling
  • Structured JSON output
  • Files changed summary
  • Clear failure output when package manager commands fail
  • Tests for manifest discovery, config parsing, and output shaping

This first version should be enough for a cron workflow to run dependency updates, run tests, and open a single grouped PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions