DEV Community

Karl Weinmeister for Google AI

Posted on • Originally published at Medium on

The future of autonomous software maintenance: a dependency update agent

Most AI tools focus on writing new code, but up to 80% of the cost of software comes from maintenance. What if an intelligent agent could handle that burden for you?

In this article, I’ll walk through an autonomous agent called dependency-director that handles one of the most common maintenance scenarios: dependency updates. It goes beyond merging dependency updates that are passing tests; it upgrades your code to match changes in the dependency. This provides a sneak peek into the future of automated engineering workflows.

Note: dependency-director is an experimental proof of concept and is not intended for production environments. Although it uses security guardrails like sandboxing and command filters, running LLM-generated code dynamically always involves security trade-offs. If you experiment with the code on GitHub, please do so in an isolated testing environment, start with the --dry-run flag, and use highly restricted API tokens.

Loop engineering for software updates

A continuous triage loop is at the center of the process. The agent scans repositories and maps every open pull request to a state and triggers an action.

When a dependency update breaks a test suite, the agent automatically clones the repository and updates the code to align with the updated dependency.

Dependency Director runs on the Google Antigravity SDK, with Gemini taking care of the reasoning. You can configure the agent like this (full version in main.py):

config = LocalAgentConfig(
    model="gemini-3.5-flash",
    system_instructions=system_instructions,
    policies=policies,
    tools=agent_tools, # 12 GitHub API tools, plus a sandboxed shell
    workspaces=[project_root, workspace_tmp],
    capabilities=types.CapabilitiesConfig(
        enable_subagents=False,
        disabled_tools=[types.BuiltinTools.RUN_COMMAND],
    ),
)
Enter fullscreen mode Exit fullscreen mode

Two lines do most of the security work. disabled_tools=[types.BuiltinTools.RUN_COMMAND] turns off the SDK’s built-in shell, so the only way the agent can run a command is through my sandboxed wrapper. And workspaces pins file operations to the project directory and a per-repo temp workspace, so the agent can’t wander through the filesystem.

Guardrails live in the tools, not the prompt

A common mistake in agent design is writing rules into the system prompt and hoping the model follows them. All important constraints are enforced in the tool functions themselves.

For example, the author of the pull request must be one of the allowed bots. The defaults are dependabot[bot] and renovate[bot].

def _check_bot_author(author: str, bots: list[BotConfig]) -> BotConfig:
    allowed = {b.author for b in bots}
    if author not in allowed:
        raise PermissionError(
            f"Security Block: Only pull requests authored by {allowed} "
            f"can be processed. This PR was authored by '{author}'."
        )
    return next(b for b in bots if b.author == author)
Enter fullscreen mode Exit fullscreen mode

There’s also a --dry-run parameter, so that you can simulate the behavior locally, without updating the pull request.

async def merge_bot_pr(owner: str, repo: str, pr_number: int) -> str:
    author = await client.get_pr_author(owner, repo, pr_number)
    _check_bot_author(author, bots)
    if dry_run:
        return f"[DRY-RUN] Would have merged PR #{pr_number} in {owner}/{repo}."
Enter fullscreen mode Exit fullscreen mode

All fixes are held up as an open PR for your review by default, unless you use --automerge.

Patching a red pull request

When a PR has a conflict, the agent follows a procedure in its system instructions located in instructions.py. It uses the code-review-and-quality skill from Addy Osmani to go beyond just making the test pass, and ensure a code review and quality standards are enforced:

RED: Retrieve logs via 'get_pr_workflow_run_logs'. Clone into a subdirectory,
then check out the PR branch:
  git fetch origin pull/<pr_number>/head:pr-<pr_number> && git checkout pr-<pr_number>
Otherwise install deps, test, fix, verify, and push to the remote branch.
Max 3 fix attempts per RED PR before skipping.
Run 'code-review-and-quality' self-review before committing.
Enter fullscreen mode Exit fullscreen mode

The agent is also very clear about what counts as a fix. It’s told to consider what’s changed in the API documentation, and not just chase a green checkmark:

- Fix root causes (types, signatures, API changes) using changelogs.
- NEVER suppress errors (type: ignore, noqa, Any) unless upstream bugs
  leave no alternative (require comment).
Enter fullscreen mode Exit fullscreen mode

Running untrusted code in a sandbox

To restrict filesystem and network operations, Dependency Director uses sandbox-runtime. It’s an open-source OS-level sandbox. Every shell command the agent runs is wrapped in it:

process = await asyncio.create_subprocess_exec(
    "srt", "--settings", active_config_path, "-c", command_line,
    cwd=target_cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env,
)
Enter fullscreen mode Exit fullscreen mode

You can configure the settings file where the sandbox is configured. The default settings allow network access to package registry domains such as PyPI, npm, crates.io. The agent is blocked from reading the home directory and writing to the .env environment variable file and .git/hooks. Here’s the bundled srt-settings.json, trimmed to a few representative entries:

{
  "network": {
    "allowedDomains": ["github.com", "pypi.org", "registry.npmjs.org"],
    "deniedDomains": ["*.ngrok.io", "*.webhook.site", "*.requestbin.com"]
  },
  "filesystem": {
    "denyRead": ["~"],
    "allowWrite": ["/tmp"],
    "denyWrite": [".env", ".git/hooks"],
    "allowGitConfig": false
  }
}
Enter fullscreen mode Exit fullscreen mode

Trying it out yourself

Solid test coverage is essential for updating dependencies. Tests give you the confidence to know that your code still functions. When you use Dependency Director, they’re absolutely required so that the agent can safely patch your code to work with the updated dependencies. For tips on effective tests, see my blog post on five essential testing patterns.

Using an AI agent does consume tokens, of course. I performed a trial run on a repo with 6 open pull requests using gemini-3.5-flash. It used about 200k tokens. At the current published rate, that’s about $0.30 USD for the run, or roughly 6 cents per PR.

The code to try out dependency-director is on GitHub for you to try. Start with --dry-run to see how it works for you!

What maintenance work would you hand to an agent first? Tell me on X, LinkedIn, or Bluesky.


Top comments (0)