Combat Agents: Automating Volatility-Based Decomposition

At Don’t Panic Labs, we frequently discuss Volatility-Based Decomposition (VBD). It is an architecture practice that groups and boundaries systems by where change occurs. Instead of organizing purely by domains or technical layers, VBD identifies parts of the codebase that change together or change frequently. We use those patterns to inform seams, ownership, and stabilization strategies.

Usually, we determine these volatilities before a project begins. But recently, I wanted to try something different. I wanted to analyze an existing software project to determine its volatilities using data.

If we find the right signals, the work itself should reveal the volatilities.

In this post, I will walk through “Combat Agents,” a system I built where four LangChain agents collaborate to evaluate code volatility using data derived directly from source code.

The Approach

We wanted an approach that moved beyond simple static analysis. We needed something dynamic and opinionated.

  • It’s data-driven: We infer volatility from real repository signals like churn, commit patterns, complexity, and dependencies.
  • It’s multi-perspective: We look through different lenses-Git history, quality risk, and architecture-to highlight different sources of instability.
  • It’s actionable: The output isn’t just a graph; it is a concise list of volatility labels with reasons, suitable for backlog items or refactor proposals.

The Agent Overview

To achieve this, we employed three specialist agents to analyze the project from different perspectives, and a fourth synthesizer agent to reconcile their findings.

Here is how the team is structured:

  1. Git-Centric Volatility Agent: This agent focuses on change patterns. It uses signals like lines changed, commits, and churn to derive concise volatility labels.
  2. Quality + Volatility Risk Agent: This agent acts as a technical debt analyst. It combines churn with grades, complexity, and cyclomatic complexity (CCN).
  3. Architectural Volatility Agent: This agent evaluates volatility across layers and dependency concentration.
  4. Synthesizer Agent: This is the closer. It selects the best agent’s set, consolidates similar items, and caps the final list to a manageable 5–10 items.

How We Use LangChain

We utilized LangChain core (specifically ChatPromptTemplate and RunnableLambda) and langchain-ollama for running local LLMs.

Each agent is created via a small wrapper that gathers perspective-specific signal summaries from a tool. We then prompt the LLM to output ONLY a JSON array of objects.

Why strict JSON?

It allows us to programmatically process the results. If the LLM fails to return valid JSON, we have a lightweight fallback that derives labels from filenames to keep the system robust.

The Inputs

To fuel these agents, we need good data. We feed them:

  • Repo-level metrics and hotspot files from Git.
  • Per-file size (nloc), complexity, dependencies, and gitChanges.
  • Function-level CCN extracted via Lizard, aggregated to file-level stats.

Prompting for Perspectives

The magic happens in the prompts. We give each agent a specific persona to ensure they stay in their lane.

  • Git Agent: “You are the Git Volatility Expert. Focus ONLY on change patterns.”
  • Quality Agent: “You are the Technical Debt & Risk Volatility Analyst. Combine volatility with quality signals.”
  • Architecture Agent: “You are the Software Architecture Volatility Analyst. Evaluate volatility across layers and dependencies.”

We enforce a constraint that they must return a maximum of 10 items, with one-to-two word labels. We don’t seed the list; we want the agents to infer themes strictly from the signals.

Synthesis and Evaluation

Once the specialists are done, we need to make a decision. We evaluate agent outputs by consensus, scoring items by their appearances across agents and source diversity.

The Synthesizer Agent picks a “winner”—usually the agent with the strongest coverage—and builds a preliminary top list.

Then, we ask the Synthesizer to merge near-duplicates. For example, if one agent finds “AuthModule” and another finds “Authentication,” the Synthesizer merges these into a single concise label.

Conclusion

Running this on existing codebases is yielding interesting results.

I don’t think I have it fully tuned in yet, but with some more testing, I believe this could yield some useful and actionable results for software architects.

You can see an example output for an Angular application here: https://gist.github.com/chadmichel/36bb0666e3986fe8d6923c394bdffdf4.

Have you experimented with using agents for architectural analysis? I’d love to hear about it. Reach out to me on X @chadmichel.

author avatar
Chad Michel Chief Technology Officer
Chad is a lifelong Nebraskan. He grew up in rural Nebraska and now lives in Lincoln. Chad and his wife have a son and daughter.

Related posts