DEV Community

Cover image for Adding SonarQube to an AI-Assisted Development Workflow

Adding SonarQube to an AI-Assisted Development Workflow

We use AI agents as coding assistants (here Claude Code) in our daily work. Not in a "vibe coding" way where you throw a prompt and hope for the best. We practice spec-driven development: detailed specifications, structured plans, context engineering through CLAUDE.md files, custom instructions, and carefully scoped tasks. The goal is to give the AI enough context to produce good code from the start.

And it mostly works. The code we get is solid. But "mostly" isn't enough when you're shipping to production. Even with good context and clear specs, an AI assistant can still produce code with security issues, excessive complexity, or subtle smells that you'd catch in a thorough review — if you had the time.

So we added SonarQube to the loop, and we let the AI fix what Sonar finds.

The setup

If you want to rely on CI based Sonar scans and reports, you need to have non-free options :

  • Sonar cloud subscription
  • SonarQube sever, developer edition (the community edition does not help much).

We wanted something that runs locally, requires no manual steps, and integrates directly into the AI agent's workflow.

A local SonarQube instance via Docker Compose:

services:
  sonarqube:
    image: sonarqube:lts-community
    ports:
      - "9000:9000"
    volumes:
      - sonar_data:/opt/sonarqube/data
Enter fullscreen mode Exit fullscreen mode

A scan script (scripts/sonar-scan.sh) that handles the full lifecycle:

  • checks that SonarQube is up
  • auto-provisions an auth token on first run
  • creates the project if needed
  • runs the scanner via Docker
  • waits for analysis to finish
  • fetches all issues
  • and writes them to a structured sonar-report.json file.

Each issue comes with a file path, line number, severity, rule ID, and a description. This structured output is what makes the automation possible — the AI agent can parse it and act on each issue directly.

A Claude Code slash command (.claude/commands/sonar.md) that ties it together. When you run /sonar, the agent:

  1. Runs bash scripts/sonar-scan.sh
  2. Reads the report — issues sorted by severity (BLOCKER, CRITICAL, MAJOR...)
  3. For each issue: reads the file, understands the rule violation, applies a minimal fix
  4. Skips generated code (API clients, etc.)
  5. Runs npm run type-check to make sure fixes don't break anything
  6. Re-scans. If new issues appeared, fixes those too.
  7. Reports what it changed and how many iterations it took.

CI enforcement via GitHub Actions on every PR:

- name: SonarQube Scan
  uses: SonarSource/sonarqube-scan-action@v5
  env:
    SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
    SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

- name: Quality Gate
  uses: SonarSource/sonarqube-quality-gate-action@v1
Enter fullscreen mode Exit fullscreen mode

How the loop works in practice

We recently built a feature with several Lit web components, services, and types — version history with diffs, draft management, conflict resolution dialogs. The AI generated it from detailed specs. The code worked, tests passed, TypeScript was happy.

Then we ran /sonar. Sonar found things like:

  • Cognitive complexity too high in some diff rendering logic
  • Unused imports left over from refactoring iterations
  • Duplicated string literals across components
  • Missing type narrowing where null dereferences were possible
  • Missing ARIA attributes on interactive elements

None of these were show-stoppers. All of them were things you'd want fixed before merging. The agent resolved them in 2-3 scan cycles without intervention.

The point isn't that the AI wrote bad code. The point is that static analysis catches a class of issues that are easy to miss during generation — and the AI is perfectly capable of fixing them when told what's wrong.

Why Sonar and not just a linter

ESLint catches a lot, but SonarQube covers ground that linters don't:

  • Security vulnerability detection (injections, hardcoded secrets, insecure patterns)
  • Cross-file duplication detection
  • Cognitive complexity scoring
  • A quality gate — a binary pass/fail, not just a list of warnings

Combined with TypeScript's type checker and your test suite, you get three independent verification layers, each catching different categories of problems.

What this looks like day-to-day

Our workflow before a PR:

  1. Write specs and plan the feature
  2. AI implements it with full context (CLAUDE.md, specs, existing code)
  3. Run /sonar — the agent scans, fixes, re-scans until clean
  4. Verify that typecheck and tests still pass
  5. Review the diff and open the PR

The Sonar step typically adds a few minutes. It's not something we run after every edit — just before we consider a feature done. Think of it as an automated pre-review pass.

Closing thoughts

If you use AI assistants for coding, you already have good reasons to invest in context engineering — giving the AI the right specs, the right constraints, the right examples. SonarQube is another form of that same idea: giving the AI structured feedback about what's not right, and letting it iterate.

The scan script, the slash command, and the CI workflow are all straightforward to set up. SonarQube Community Edition is free. The scripts are plain bash. This works with any AI coding tool that can run shell commands and read structured output.

The code is on GitHub if you want to look at the implementation.

Link to the repository

Top comments (0)