Introduction
🚧 Early Prototype - This project is under active development and APIs may change
Debtmap is a fast code complexity and technical debt analyzer written in Rust. Debtmap identifies which code to refactor for maximum cognitive debt reduction and which code to test for maximum risk reduction, providing data-driven prioritization for both.
What is Debtmap?
Unlike traditional static analysis tools that simply flag complex code, Debtmap answers two critical questions:
- “What should I refactor to reduce cognitive burden?” - Identifies overly complex code that slows down development
- “What should I test first to reduce the most risk?” - Pinpoints untested complex code that threatens stability
Debtmap analyzes your codebase to identify complexity hotspots, technical debt patterns, and architectural risks. It supports Rust, Python, JavaScript, and TypeScript with full AST parsing and analysis capabilities. Rust includes additional advanced features like macro expansion and trait tracking.
What Makes Debtmap Different:
- Entropy-Based Complexity Analysis: Uses information theory to distinguish genuinely complex code from pattern-based repetitive code, reducing false positives by up to 70%
- Coverage-Risk Correlation: The only tool that combines complexity metrics with test coverage to identify genuinely risky code (high complexity + low coverage = critical risk)
- Risk-Driven Prioritization: Prioritizes refactoring and testing efforts based on complexity, coverage, and dependency factors
- Actionable Guidance: Provides specific recommendations like “extract nested conditions” or “split this 80-line function” rather than just flagging issues
- Performance: 10-100x faster than Java/Python-based competitors (written in Rust with parallel processing)
Why Use Debtmap?
Debtmap helps you make data-driven decisions about where to focus your refactoring and testing efforts:
- Identify Complexity - Find complex functions and modules that need refactoring, with concrete metrics showing which changes will have the most impact
- Detect Technical Debt - Discover 30+ debt patterns including code smells, security vulnerabilities, resource management issues, and architectural problems
- Assess Risk - Prioritize improvements based on sophisticated risk scoring that combines complexity, test coverage, and dependency impact
- Track Quality - Monitor code quality metrics over time with the
compare
command (which can track improvements against implementation plan targets) to verify that refactoring efforts achieved their goals - Get Actionable Recommendations - Receive specific guidance like “refactoring this will reduce complexity by 60%” or “testing this will reduce risk by 5%”
- Automated Debt Reduction - Integrates with Prodigy workflows for AI-driven automated refactoring with iterative validation and testing
Key Features
Analysis Capabilities
- Multi-language support - Full support for Rust, Python, JavaScript, and TypeScript with AST parsing, complexity analysis, and debt detection
- Entropy-based complexity analysis - Distinguishes between genuinely complex code and pattern-based repetitive code using information theory
- Token classification system - Advanced token categorization with weighted entropy for accurate complexity assessment
- Comprehensive debt detection - Identifies 30+ technical debt patterns across security (5 types), code organization (god objects, feature envy, magic values), resource management (5 types), testing quality (3 types), and error handling (4 types)
- Security vulnerability detection - Finds hardcoded secrets, weak crypto, SQL injection risks, and unsafe code patterns
- Resource management analysis - Identifies inefficient allocations, nested loops, and blocking I/O patterns
- Code organization analysis - Detects god objects, feature envy, primitive obsession, and magic values
- Testing quality assessment - Analyzes test complexity, flaky patterns, and assertion quality
- Context-aware analysis - Reduces false positives through intelligent context detection (enabled by default)
Risk Analysis & Prioritization
- Coverage-based risk analysis - Correlates complexity with test coverage to identify truly risky code
- Risk-driven testing recommendations - Prioritizes testing efforts based on complexity-coverage correlation and dependency impact
- Call graph analysis - Tracks upstream callers and downstream callees to understand dependency impact
- Tiered prioritization - Surfaces critical architectural issues above simple testing gaps
- Quantified impact - Shows concrete metrics like “refactoring this will reduce complexity by 60%”
Performance & Output
- Parallel processing - Built with Rust and Rayon for blazing-fast analysis of large codebases
- Multiple output formats - JSON, Markdown, and human-readable terminal formats
- Configurable thresholds - Customize complexity and duplication thresholds to match your standards
- Incremental analysis - Smart caching system for analyzing only changed files
- Intelligent caching - Smart cache system with automatic pruning, configurable strategies (LRU, LFU, FIFO), and environment-based configuration for fast repeated analysis
- Verbosity controls - Multiple verbosity levels (-v, -vv, -vvv) for progressive detail
Configuration & Customization
- Flexible suppression - Inline comment-based suppression for specific code sections
- Configuration file -
.debtmap.toml
for project-specific settings - Test-friendly - Easily exclude test fixtures and example code from debt analysis
- Macro expansion support - Handles Rust macro expansions with configurable warnings
Commands
analyze
- Comprehensive debt analysis with unified prioritizationvalidate
- Enforce quality thresholds in CI/CD pipelinescompare
- Track improvements over time and verify refactoring goalsinit
- Generate configuration file with sensible defaults
Target Audience
Debtmap is designed for:
- Development teams - Get concrete metrics for planning sprints. Know exactly which refactoring will reduce complexity by 60% or which function needs 6 unit tests for full coverage.
- Engineering managers - Track quality trends over time with the
compare
command. Monitor whether refactoring efforts are actually improving codebase health. - Code reviewers - Focus reviews on high-risk areas identified by Debtmap. Prioritize reviewing untested complex code over simple utility functions.
- Developers refactoring legacy codebases - Receive actionable guidance like “extract nested conditions”, “split this 80-line function into 3 smaller functions”, or “add error handling for this catch block”.
Getting Started
Ready to analyze your codebase? Check out:
- Installation - Installing Debtmap on your system
- Getting Started - Installation and first analysis
- Analysis Guide - Understanding the metrics and output
- Output Formats - JSON, Markdown, and terminal formats
Getting Started
This guide will help you install Debtmap and run your first analysis in just a few minutes.
Prerequisites
Before installing Debtmap, you’ll need:
- For pre-built binaries: No prerequisites! The install script handles everything.
- For cargo install or building from source:
- Rust toolchain (rustc and cargo)
- Supported platforms: Linux, macOS, Windows
- Rust edition 2021 or later
Optional (for coverage-based risk analysis):
- Rust projects:
cargo-tarpaulin
for coverage data - JavaScript/TypeScript: Jest or other tools generating LCOV format
- Python: pytest with coverage plugin
Installation
Quick Install (Recommended)
Install the latest release with a single command:
curl -sSL https://raw.githubusercontent.com/iepathos/debtmap/master/install.sh | bash
Or with wget:
wget -qO- https://raw.githubusercontent.com/iepathos/debtmap/master/install.sh | bash
This will:
- Automatically detect your OS and architecture
- Download the appropriate pre-built binary from the latest GitHub release
- Install debtmap to
~/.cargo/bin
if it exists, otherwise~/.local/bin
- Offer to automatically add the install directory to your PATH if needed
Using Cargo
If you have Rust installed:
cargo install debtmap
From Source
For the latest development version:
# Clone the repository
git clone https://github.com/iepathos/debtmap.git
cd debtmap
# Build and install
cargo install --path .
Verify Installation
After installation, verify Debtmap is working:
# Check version
debtmap --version
# See available commands
debtmap --help
Common installation issues:
- Binary not in PATH: Add
~/.cargo/bin
or~/.local/bin
to your PATHexport PATH="$HOME/.cargo/bin:$PATH" # Add to ~/.bashrc or ~/.zshrc
- Permission issues: Run the install script with your current user (don’t use sudo)
- Cargo not found: Install Rust from https://rustup.rs
Quick Start
Here are the most common commands to get you started:
# Analyze current directory (simplest command)
debtmap analyze .
# Analyze with coverage data for risk scoring (recommended)
# Note: --lcov is a shorthand alias for --coverage-file
debtmap analyze . --lcov target/coverage/lcov.info
# Generate coverage first (for Rust projects)
cargo tarpaulin --out lcov --output-dir target/coverage
debtmap analyze . --lcov target/coverage/lcov.info
# Analyze with custom thresholds
# Note: threshold-duplication specifies minimum lines of duplicated code to detect
debtmap analyze ./src --threshold-complexity 15 --threshold-duplication 50
# Output as JSON (for CI/CD integration)
debtmap analyze ./src --format json --output report.json
# Show only top 10 high-priority issues
debtmap analyze . --top 10
# Initialize configuration file for project-specific settings
debtmap init
# Validate against thresholds (CI/CD integration)
debtmap validate ./src --max-debt-density 5.0
# Compare before/after to track improvements
debtmap analyze . --format json --output before.json
# ... make improvements ...
debtmap analyze . --format json --output after.json
debtmap compare --before before.json --after after.json
# Advanced comparison: focus on specific function
debtmap compare --before before.json --after after.json --target-location src/main.rs:main:10
# Extract target from implementation plan
debtmap compare --before before.json --after after.json --plan IMPLEMENTATION_PLAN.md
Advanced Options
Debtmap provides many powerful options to customize your analysis:
Verbosity Levels:
# Show main factors contributing to scores
debtmap analyze . -v
# Show detailed calculations
debtmap analyze . -vv
# Show all debug information
debtmap analyze . -vvv
Filtering and Prioritization:
# Only show high-priority items
debtmap analyze . --min-priority high
# Filter by specific categories
debtmap analyze . --filter Architecture,Testing
# Group results by debt category
debtmap analyze . --group-by-category
Cache Management:
# Skip cache for fresh analysis
debtmap analyze . --no-cache
# Clear cache and rebuild
debtmap analyze . --clear-cache
# View cache statistics
debtmap analyze . --cache-stats
# Specify custom cache location
debtmap analyze . --cache-location /custom/path
# Migrate cache from local to shared location
debtmap analyze . --migrate-cache
Performance Control:
# Limit parallel jobs
debtmap analyze . --jobs 4
# Disable parallel processing
debtmap analyze . --no-parallel
Output Control:
# Plain output (no colors/emoji, for CI/CD)
debtmap analyze . --plain
# Compact summary output
debtmap analyze . --summary
# Control aggregation behavior
debtmap analyze . --aggregate-only # Show only aggregated results
debtmap analyze . --no-aggregation # Skip aggregation entirely
debtmap analyze . --aggregation-method sum # Choose aggregation method
# Adjust detail level in output
debtmap analyze . --detail-level high # More detailed output
Expert Options:
These advanced options are available for power users and specialized use cases:
# Analysis behavior
--semantic-off # Disable semantic analysis
--no-context-aware # Disable context-aware analysis
--multi-pass # Enable multi-pass analysis for deeper insights
--validate-loc # Validate lines of code calculations
# Rust-specific options
--verbose-macro-warnings # Show detailed macro expansion warnings
--show-macro-stats # Display macro usage statistics
# Filtering and thresholds
--threshold-preset <name> # Use predefined threshold preset
--min-problematic <count> # Minimum problematic items to report
--max-files <count> # Limit analysis to N files
--no-god-object # Disable god object detection
# Advanced reporting
--attribution # Include code attribution information
For detailed documentation of these options, run debtmap analyze --help
.
First Analysis
Let’s run your first analysis! Navigate to a project directory and run:
debtmap analyze .
What happens during analysis:
- File Discovery - Debtmap scans your project for supported source files (Rust, Python, JavaScript, TypeScript)
- Parsing - Each file is parsed into an Abstract Syntax Tree (AST)
- Metrics Calculation - Complexity, debt patterns, and risk scores are computed
- Prioritization - Results are ranked by priority (CRITICAL, HIGH, MEDIUM, LOW)
- Output - Results are displayed in your chosen format
Expected timing: Analyzing a 10,000 LOC project typically takes 2-5 seconds. The first run may be slightly slower as Debtmap builds its cache.
About Caching: Debtmap caches parsed ASTs and computed metrics to speed up subsequent analyses:
- Cache location:
XDG_CACHE_HOME/debtmap
on Linux,~/Library/Caches/debtmap
on macOS,%LOCALAPPDATA%/debtmap
on Windows - What’s cached: Parsed ASTs and computed metrics for each file
- Invalidation: Cache is automatically invalidated when files are modified
- Management: Use
--clear-cache
to clear,--no-cache
to skip, or--cache-stats
to view statistics
Language support:
- Rust: Full support with advanced features (trait detection, purity analysis, call graphs)
- Python: Partial support (complexity metrics, basic debt detection)
- JavaScript/TypeScript: Partial support (complexity metrics, basic debt detection)
Example Output
When you run debtmap analyze .
, you’ll see output like this:
════════════════════════════════════════════
PRIORITY TECHNICAL DEBT FIXES
════════════════════════════════════════════
🎯 TOP 3 RECOMMENDATIONS (by unified priority)
#1 SCORE: 8.9 [CRITICAL]
├─ TEST GAP: ./src/analyzers/rust_call_graph.rs:38 add_function_to_graph()
├─ ACTION: Add 6 unit tests for full coverage
├─ IMPACT: Full test coverage, -3.7 risk
├─ COMPLEXITY: cyclomatic=6, branches=6, cognitive=8, nesting=2, lines=32
├─ DEPENDENCIES: 0 upstream, 11 downstream
└─ WHY: Business logic with 0% coverage, manageable complexity (cyclo=6, cog=8)
#2 SCORE: 8.9 [CRITICAL]
├─ TEST GAP: ./src/debt/smells.rs:196 detect_data_clumps()
├─ ACTION: Add 5 unit tests for full coverage
├─ IMPACT: Full test coverage, -3.7 risk
├─ COMPLEXITY: cyclomatic=5, branches=5, cognitive=11, nesting=5, lines=31
├─ DEPENDENCIES: 0 upstream, 4 downstream
└─ WHY: Business logic with 0% coverage, manageable complexity (cyclo=5, cog=11)
#3 SCORE: 8.6 [CRITICAL]
├─ TEST GAP: ./src/risk/context/dependency.rs:247 explain()
├─ ACTION: Add 5 unit tests for full coverage
├─ IMPACT: Full test coverage, -3.6 risk
├─ COMPLEXITY: cyclomatic=5, branches=5, cognitive=9, nesting=1, lines=24
├─ DEPENDENCIES: 0 upstream, 1 downstream
└─ WHY: Business logic with 0% coverage, manageable complexity (cyclo=5, cog=9)
📊 TOTAL DEBT SCORE: 4907
📈 OVERALL COVERAGE: 67.12%
Understanding the Output
Let’s break down what this output means:
Priority Levels
- CRITICAL (9.0-10.0): Immediate action required - high complexity with no test coverage
- HIGH (7.0-8.9): Should be addressed soon - moderate-high complexity with poor coverage
- MEDIUM (5.0-6.9): Plan for next sprint - moderate complexity or partial coverage gaps
- LOW (3.0-4.9): Nice to have - well-tested or simple functions
Note: These are default priority thresholds. You can customize them in .debtmap.toml
under the [tiers]
section to match your team’s standards.
Key Metrics
-
Unified Score (0-10 scale): Overall priority combining complexity, coverage, and dependencies
- Higher score = higher priority
- Takes into account multiple risk factors
-
Debt Type: Category of the issue
TestGap
: Missing test coverageComplexity
: Exceeds complexity thresholdsDuplication
: Repeated code blocksCodeSmell
: Anti-patterns and bad practices
-
Complexity Metrics:
- Cyclomatic: Number of decision points (branches, loops)
- Cognitive: How difficult the code is to understand
- Nesting: Maximum indentation depth
- Lines: Function length
-
Dependencies:
- Upstream callers: Functions that call this function
- Downstream callees: Functions this function calls
- More dependencies = higher impact when this code breaks
Recommendation Structure
Each recommendation shows:
- ACTION: What you should do (e.g., “Add 6 unit tests”)
- IMPACT: Expected improvement (e.g., “Full test coverage, -3.7 risk”)
- WHY: The reasoning behind this recommendation
Organizing Results
When analyzing large codebases, you can organize and filter results to focus on specific areas:
Group by Debt Category:
debtmap analyze . --group-by-category
This organizes results by type: Architecture, Testing, Performance, CodeQuality
Filter by Priority:
# Show only high and critical priority items
debtmap analyze . --min-priority high
# Combine with --top to limit results
debtmap analyze . --min-priority high --top 10
Filter by Category:
# Focus on specific debt types
debtmap analyze . --filter Architecture,Testing
# Available categories: Architecture, Testing, Performance, CodeQuality
These filtering options help you focus on specific types of technical debt, making it easier to plan targeted improvements.
Summary Statistics
-
Total Debt Score: Sum of all debt scores across your codebase
- Lower is better
- Track over time to measure improvement
-
Overall Coverage: Percentage of code covered by tests
- Only shown when coverage data is provided
Output Formats
Debtmap supports multiple output formats:
- Terminal (default): Human-readable colored output with tables
- JSON: Machine-readable format for CI/CD integration
- Markdown: Documentation-friendly format for reports
Example JSON output:
# By default, JSON uses legacy format
debtmap analyze . --format json --output report.json
# For the new unified format (with consistent structure and type field):
debtmap analyze . --format json --output-format unified --output report.json
JSON Format Options:
- legacy (default): Uses
{File: {...}}
and{Function: {...}}
wrappers for backward compatibility with existing tools - unified: New format (spec 108) with consistent structure and
type
field for all items
Recommendation: Use unified
for new integrations, legacy
only for compatibility with existing tooling.
Example Markdown output:
debtmap analyze . --format markdown --output report.md
What’s Next?
Now that you’ve run your first analysis, explore these topics:
- Analysis Guide - Deep dive into complexity metrics, debt patterns, and risk scoring
- Output Formats - Detailed guide to JSON schema and integration options
- Configuration - Customize thresholds and filters with
.debtmap.toml
- CI/CD Integration - Use the
validate
command to enforce quality gates
Generate a Configuration File
Create a project-specific configuration:
debtmap init
This creates a .debtmap.toml
file with sensible defaults that you can customize for your project.
Key Configuration Options:
The configuration file allows you to customize:
- Threshold customization - Adjust complexity, duplication, and file size thresholds
- Scoring weights - Fine-tune how coverage, complexity, and dependencies are weighted
- Language selection - Enable/disable specific language analyzers
- Ignore patterns - Exclude test files or generated code from analysis
- God object thresholds - Configure what constitutes a “god object” anti-pattern
- Entropy analysis - Control entropy-based complexity detection
- Priority tiers - Customize CRITICAL/HIGH/MEDIUM/LOW threshold ranges
See the Configuration chapter for complete documentation of all available options.
Try Analysis with Coverage
For more accurate risk assessment, run analysis with coverage data:
# For Rust projects
cargo tarpaulin --out lcov --output-dir target/coverage
debtmap analyze . --lcov target/coverage/lcov.info
# For Python projects
pytest --cov --cov-report=lcov
debtmap analyze . --lcov coverage.lcov
# For JavaScript/TypeScript projects
jest --coverage --coverageReporters=lcov
debtmap analyze . --lcov coverage/lcov.info
Coverage data helps Debtmap identify truly risky code - functions that are both complex AND untested.
Need help? Report issues at https://github.com/iepathos/debtmap/issues
CLI Reference
Complete reference for Debtmap command-line interface.
Quick Start
# Basic analysis
debtmap analyze src/
# With coverage integration
debtmap analyze src/ --coverage-file coverage.lcov
# Generate JSON report
debtmap analyze . --format json --output report.json
# Show top 10 priority items only
debtmap analyze . --top 10 --min-priority high
# Initialize configuration and validate
debtmap init
debtmap validate . --config debtmap.toml
Commands
Debtmap provides four main commands:
analyze
Analyze code for complexity and technical debt.
Usage:
debtmap analyze <PATH> [OPTIONS]
Arguments:
<PATH>
- Path to analyze (file or directory)
Description: Primary command for code analysis. Supports multiple output formats (json, markdown, terminal), coverage file integration, caching, parallel processing, context-aware risk analysis, and comprehensive filtering options.
See Options section below for all available flags.
init
Initialize a Debtmap configuration file.
Usage:
debtmap init [OPTIONS]
Options:
-f, --force
- Force overwrite existing config
Description:
Creates a debtmap.toml
configuration file in the current directory with default settings. Use --force
to overwrite an existing configuration file.
validate
Validate code against thresholds defined in configuration file.
Usage:
debtmap validate <PATH> [OPTIONS]
Arguments:
<PATH>
- Path to analyze
Options:
Configuration & Output:
-c, --config <CONFIG>
- Configuration file path-f, --format <FORMAT>
- Output format: json, markdown, terminal-o, --output <OUTPUT>
- Output file path (defaults to stdout)
Coverage & Context:
--coverage-file <PATH>
/--lcov <PATH>
- LCOV coverage file for risk analysis--context
/--enable-context
- Enable context-aware risk analysis--context-providers <PROVIDERS>
- Context providers to use (comma-separated)--disable-context <PROVIDERS>
- Disable specific context providers
Thresholds & Validation:
--max-debt-density <N>
- Maximum debt density allowed (per 1000 LOC)
Display Filtering:
--top <N>
/--head <N>
- Show only top N priority items--tail <N>
- Show only bottom N priority items-s, --summary
- Use summary format with tiered priority display
Analysis Control:
--semantic-off
- Disable semantic analysis (fallback mode)
Debugging & Verbosity:
-v, --verbose
- Increase verbosity level (can be repeated: -v, -vv, -vvv)
Description:
Similar to analyze
but enforces thresholds defined in configuration file. Returns non-zero exit code if thresholds are exceeded, making it suitable for CI/CD integration.
The validate
command supports a focused subset of analyze
options, primarily for output control, coverage integration, context-aware analysis, and display filtering. The validate command does not support --threshold-complexity
, --threshold-duplication
, or --threshold-preset
flags (these are analyze-only). Instead, configure thresholds in the .debtmap.toml
config file. Performance options like --jobs
, --cache-*
, and --languages
are also not available in validate.
Exit Codes:
0
- Success (no errors, all thresholds passed)- Non-zero - Failure (errors occurred or thresholds exceeded)
compare
Compare two analysis results and generate a diff report.
Usage:
debtmap compare --before <FILE> --after <FILE> [OPTIONS]
Required Options:
--before <FILE>
- Path to “before” analysis JSON--after <FILE>
- Path to “after” analysis JSON
Optional Target Location:
--plan <FILE>
- Path to implementation plan (to extract target location)--target-location <LOCATION>
- Target location in formatfile:function:line
Note: --plan
and --target-location
are mutually exclusive options. Using both together will cause a CLI error. Use one or the other to specify the target location.
Output Options:
-f, --format <FORMAT>
- Output format: json, markdown, terminal (default: json)-o, --output <OUTPUT>
- Output file (defaults to stdout)
Description: Compares two analysis results and generates a diff showing improvements or regressions in code quality metrics.
Options
Options are organized by category for clarity. Most options apply to the analyze
command, with a subset available for validate
.
Output Control
Control how analysis results are formatted and displayed.
Format Options:
-f, --format <FORMAT>
- Output format: json, markdown, terminal (default: terminal for analyze)--output-format <JSON_FORMAT>
- JSON structure format: legacy or unified (default: legacy)legacy
- Current format with{File: {...}}
and{Function: {...}}
wrappersunified
- New format with consistent structure and ‘type’ field
-o, --output <OUTPUT>
- Output file path (defaults to stdout)--plain
- Plain output mode: ASCII-only, no colors, no emoji, machine-parseable
Display Filtering:
--top <N>
/--head <N>
- Show only top N priority items--tail <N>
- Show only bottom N priority items (lowest priority)-s, --summary
- Use summary format with tiered priority display (compact output)--min-priority <PRIORITY>
- Minimum priority to display: low, medium, high, critical--filter <CATEGORIES>
- Filter by debt categories (comma-separated)--aggregate-only
- Show only aggregated file-level scores--group-by-category
- Group output by debt category
Analysis Control
Configure analysis behavior, thresholds, and language selection.
Thresholds:
--threshold-complexity <N>
- Complexity threshold (default: 10) [analyze command]--threshold-duplication <N>
- Duplication threshold in lines (default: 50) [analyze command]--threshold-preset <PRESET>
- Complexity threshold preset: strict, balanced, lenient [analyze command]strict
- Strict thresholds for high code quality standardsbalanced
- Balanced thresholds for typical projects (default)lenient
- Lenient thresholds for legacy or complex domains
--max-debt-density <N>
- Maximum debt density allowed per 1000 LOC [validate command]
Note: Threshold options (--threshold-complexity
, --threshold-duplication
, --threshold-preset
) are command-line options for the analyze
command. For the validate
command, these thresholds are configured via the --config
file (debtmap.toml
) rather than as command-line flags.
Language Selection:
--languages <LANGS>
- Comma-separated list of languages to analyze- Example:
--languages rust,python,javascript
- Supported: rust, python, javascript, typescript
- Example:
Analysis Modes:
--semantic-off
- Disable semantic analysis (fallback mode)--no-context-aware
- Disable context-aware false positive reduction (enabled by default)--multi-pass
- Enable multi-pass analysis with attribution--attribution
- Show complexity attribution details
Context & Coverage
Enable context-aware risk analysis and integrate test coverage data.
Context-Aware Risk Analysis:
--context
/--enable-context
- Enable context-aware risk analysis--context-providers <PROVIDERS>
- Context providers to use (comma-separated)- Available:
critical_path
,dependency
,git_history
- Example:
--context-providers critical_path,git_history
- Available:
--disable-context <PROVIDERS>
- Disable specific context providers (comma-separated)
Coverage Integration:
--coverage-file <PATH>
/--lcov <PATH>
- LCOV coverage file for risk analysis- Coverage data dampens debt scores for well-tested code (multiplier = 1.0 - coverage)
- Surfaces untested complex functions as higher priority
- Total debt score with coverage ≤ score without coverage
--validate-loc
- Validate LOC consistency across analysis modes (with/without coverage)
Performance & Caching
Optimize analysis performance through parallelization and caching.
Parallel Processing:
--no-parallel
- Disable parallel call graph construction (enabled by default)-j, --jobs <N>
- Number of threads for parallel processing0
= use all available CPU cores (default)- Specify number to limit thread count
Caching:
--no-cache
- Disable caching for this run (caching is enabled by default)--clear-cache
- Clear cache before running analysis--force-cache-rebuild
- Force cache rebuild (same as –clear-cache)--cache-stats
- Show cache statistics and location--migrate-cache
- Migrate cache from local to shared location--cache-location <LOCATION>
- Cache location strategy: local, shared, or path- Can also be set via
DEBTMAP_CACHE_DIR
environment variable - Affects where analysis results are cached for faster subsequent runs
- Can also be set via
Other Performance:
--max-files <N>
- Maximum number of files to analyze (0 = no limit)
Debugging & Verbosity
Control diagnostic output and debugging information.
Verbosity Levels:
-v, --verbose
- Increase verbosity level (can be repeated: -v, -vv, -vvv)-v
- Show main score factors-vv
- Show detailed calculations-vvv
- Show all debug information
Specialized Debugging:
--verbose-macro-warnings
- Show verbose macro parsing warnings (Rust analysis)--show-macro-stats
- Show macro expansion statistics at end of analysis--detail-level <LEVEL>
- Detail level for diagnostic reports- Options: summary, standard, comprehensive, debug (default: standard)
Aggregation
Control file-level aggregation and god object detection.
File Aggregation:
--aggregate-only
- Show only aggregated file-level scores--no-aggregation
- Disable file-level aggregation--aggregation-method <METHOD>
- File aggregation method (default: weighted_sum)- Options: sum, weighted_sum, logarithmic_sum, max_plus_average
--min-problematic <N>
- Minimum number of problematic functions for file aggregation--no-god-object
- Disable god object detection
Option Aliases
Common option shortcuts and aliases for convenience:
--lcov
is alias for--coverage-file
--enable-context
is alias for--context
--head
is alias for--top
-s
is short form for--summary
-v
is short form for--verbose
-f
is short form for--format
-o
is short form for--output
-c
is short form for--config
-j
is short form for--jobs
Deprecated Options
The following options are deprecated and should be migrated:
--cache
(hidden) - Deprecated: caching is now enabled by default- Migration: Remove this flag, use
--no-cache
to disable if needed
- Migration: Remove this flag, use
--explain-score
(hidden) - Deprecated: use-v
instead- Migration: Use
-v
,-vv
, or-vvv
for increasing verbosity levels
- Migration: Use
Configuration
Configuration File
Created via debtmap init
command. The configuration file (debtmap.toml
) is used by the validate
command for threshold enforcement and default settings.
Creating Configuration:
# Create new config
debtmap init
# Overwrite existing config
debtmap init --force
Environment Variables
DEBTMAP_CACHE_DIR
- Override default cache directory location- Can also be set via
--cache-location
flag - Affects where analysis results are cached for faster subsequent runs
- Can also be set via
Getting Help
Get help for any command:
# General help
debtmap --help
# Command-specific help
debtmap analyze --help
debtmap validate --help
debtmap compare --help
debtmap init --help
Common Workflows
Basic Analysis
Analyze a project and view results in terminal:
debtmap analyze src/
Generate JSON report for further processing:
debtmap analyze . --format json --output report.json
Generate Markdown report:
debtmap analyze . --format markdown --output report.md
Coverage-Integrated Analysis
Analyze with test coverage to surface untested complex code:
# Generate coverage file first (example for Rust)
cargo tarpaulin --out lcov
# Run analysis with coverage
debtmap analyze src/ --coverage-file lcov.info
Coverage dampens debt scores for well-tested code, making untested complex functions more visible.
Context-Aware Analysis
Enable context providers for risk-aware prioritization:
# Use all context providers
debtmap analyze . --context
# Use specific context providers
debtmap analyze . --context --context-providers critical_path,git_history
Context-aware analysis reduces false positives and prioritizes code based on:
- Critical execution paths
- Dependency relationships
- Git history (change frequency)
Filtered & Focused Analysis
Show only top priority items:
debtmap analyze . --top 10 --min-priority high
Filter by specific debt categories:
debtmap analyze . --filter complexity,duplication
Use summary mode for compact output:
debtmap analyze . --summary
Show only file-level aggregations:
debtmap analyze . --aggregate-only
Performance Tuning
Control parallelization:
# Use 8 threads
debtmap analyze . --jobs 8
# Disable parallel processing
debtmap analyze . --no-parallel
Manage caching:
# Use shared cache location
debtmap analyze . --cache-location shared
# Clear cache and rebuild
debtmap analyze . --clear-cache
# Show cache statistics
debtmap analyze . --cache-stats
Limit analysis scope:
# Analyze maximum 100 files
debtmap analyze . --max-files 100
# Analyze specific languages only
debtmap analyze . --languages rust,python
CI/CD Integration
Use the validate
command in CI/CD pipelines:
# Initialize configuration (one time)
debtmap init
# Edit debtmap.toml to set thresholds
# ...
# In CI pipeline: validate against thresholds
debtmap validate . --config debtmap.toml --max-debt-density 50
The validate
command returns non-zero exit code if thresholds are exceeded, failing the build.
Comparison & Tracking
Compare analysis results before and after changes:
# Before changes
debtmap analyze . --format json --output before.json
# Make code changes...
# After changes
debtmap analyze . --format json --output after.json
# Generate comparison report
debtmap compare --before before.json --after after.json --format markdown
With implementation plan:
debtmap compare --before before.json --after after.json --plan IMPLEMENTATION_PLAN.md
Debugging Analysis
Increase verbosity to understand scoring:
# Show main score factors
debtmap analyze src/ -v
# Show detailed calculations
debtmap analyze src/ -vv
# Show all debug information
debtmap analyze src/ -vvv
Show macro expansion statistics (Rust):
debtmap analyze . --show-macro-stats --verbose-macro-warnings
Use detailed diagnostic reports:
debtmap analyze . --detail-level comprehensive
Examples
Basic Analysis
# Analyze current directory
debtmap analyze .
# Analyze specific directory
debtmap analyze src/
# Generate JSON output
debtmap analyze . --format json --output report.json
With Coverage
# Analyze with LCOV coverage file
debtmap analyze src/ --coverage-file coverage.lcov
# Alternative alias
debtmap analyze src/ --lcov coverage.lcov
Context-Aware Analysis
# Enable all context providers
debtmap analyze . --context
# Use specific context providers
debtmap analyze . --context --context-providers critical_path,git_history
# Disable specific providers
debtmap analyze . --context --disable-context dependency
Filtered Output
# Top 10 priority items only
debtmap analyze . --top 10
# High priority and above
debtmap analyze . --min-priority high
# Specific categories
debtmap analyze . --filter complexity,duplication
# Summary format
debtmap analyze . --summary
# Group by category
debtmap analyze . --group-by-category
Performance Tuning
# Use 8 threads
debtmap analyze . --jobs 8
# Disable parallelization
debtmap analyze . --no-parallel
# Limit file count
debtmap analyze . --max-files 100
# Shared cache
debtmap analyze . --cache-location shared
# Clear and rebuild cache
debtmap analyze . --clear-cache
Validation
# Initialize config
debtmap init --force
# Validate against config
debtmap validate . --config debtmap.toml
# With max debt density threshold
debtmap validate . --max-debt-density 50
Comparison
# Compare two analyses
debtmap compare --before before.json --after after.json
# With markdown output
debtmap compare --before before.json --after after.json --format markdown
# With implementation plan
debtmap compare --before before.json --after after.json --plan IMPLEMENTATION_PLAN.md
# With target location
debtmap compare --before before.json --after after.json --target-location "src/main.rs:process_file:42"
Language Selection
# Analyze only Rust files
debtmap analyze . --languages rust
# Multiple languages
debtmap analyze . --languages rust,python,javascript
Threshold Configuration
# Custom complexity threshold
debtmap analyze . --threshold-complexity 15
# Use preset
debtmap analyze . --threshold-preset strict
# Custom duplication threshold
debtmap analyze . --threshold-duplication 100
Plain/Machine-Readable Output
# Plain output (no colors, no emoji)
debtmap analyze . --plain
# Combine with JSON for CI
debtmap analyze . --format json --plain --output report.json
Command Compatibility Matrix
Option | analyze | validate | compare | init |
---|---|---|---|---|
<PATH> argument | ✓ | ✓ | ✗ | ✗ |
--format | ✓ | ✓ | ✓ | ✗ |
--output | ✓ | ✓ | ✓ | ✗ |
--coverage-file | ✓ | ✓ | ✗ | ✗ |
--context | ✓ | ✓ | ✗ | ✗ |
--threshold-* | ✓ | ✗ | ✗ | ✗ |
--top / --tail | ✓ | ✓ | ✗ | ✗ |
--cache-* | ✓ | ✗ | ✗ | ✗ |
--jobs | ✓ | ✗ | ✗ | ✗ |
--verbose | ✓ | ✓ | ✗ | ✗ |
--config | ✗ | ✓ | ✗ | ✗ |
--before / --after | ✗ | ✗ | ✓ | ✗ |
--force | ✗ | ✗ | ✗ | ✓ |
Note: The validate
command supports output control (--format
, --output
), coverage integration (--coverage-file
), context-aware analysis (--context
), display filtering (--top
, --tail
, --summary
), and verbosity options (--verbose
) from the analyze
command. Analysis thresholds (--threshold-complexity
, --threshold-duplication
, --threshold-preset
) are configured via the --config
file rather than as command-line options. Performance options like --cache-*
and --jobs
are specific to the analyze
command.
Troubleshooting
Performance Issues
Problem: Analysis is slow on large codebases
Solutions:
# Use more threads (if you have CPU cores available)
debtmap analyze . --jobs 16
# Enable caching (on by default, but ensure it's not disabled)
debtmap analyze . # caching is automatic
# Use shared cache for team
debtmap analyze . --cache-location shared
# Limit analysis scope
debtmap analyze . --max-files 500 --languages rust
Memory Issues
Problem: Analysis runs out of memory
Solutions:
# Disable parallelization
debtmap analyze . --no-parallel
# Limit file count
debtmap analyze . --max-files 100
# Analyze in batches by language
debtmap analyze . --languages rust
debtmap analyze . --languages python
Output Issues
Problem: Terminal output has garbled characters
Solution:
# Use plain mode
debtmap analyze . --plain
Problem: Want machine-readable output
Solution:
# Use JSON with plain mode
debtmap analyze . --format json --plain --output report.json
Cache Issues
Problem: Stale cached results
Solutions:
# Clear cache
debtmap analyze . --clear-cache
# Check cache statistics
debtmap analyze . --cache-stats
# Disable cache temporarily
debtmap analyze . --no-cache
Threshold Issues
Problem: Too many items flagged
Solutions:
# Use lenient preset
debtmap analyze . --threshold-preset lenient
# Increase threshold
debtmap analyze . --threshold-complexity 20
# Filter to high priority only
debtmap analyze . --min-priority high
Problem: Not enough items flagged
Solutions:
# Use strict preset
debtmap analyze . --threshold-preset strict
# Lower threshold
debtmap analyze . --threshold-complexity 5
# Show all items
debtmap analyze . --min-priority low
Best Practices
Regular Analysis
Run analysis regularly to track code quality trends:
# Daily in CI
debtmap validate . --config debtmap.toml
# Weekly deep analysis with coverage
debtmap analyze . --coverage-file coverage.lcov --format json --output weekly-report.json
Team Workflows
Use shared cache for consistent team experience:
# Set environment variable for all team members
export DEBTMAP_CACHE_DIR=/shared/team/debtmap-cache
# Or use flag
debtmap analyze . --cache-location shared
Performance Optimization
For large codebases:
# Use maximum parallelization
debtmap analyze . --jobs 0 # 0 = all cores
# Cache aggressively
debtmap analyze . --cache-location shared
# Focus on changed files in CI
# (implement via custom scripts to analyze git diff)
Integration with Coverage
Always analyze with coverage when available:
# Rust example
cargo tarpaulin --out lcov
debtmap analyze src/ --coverage-file lcov.info
# Python example
pytest --cov --cov-report=lcov
debtmap analyze . --coverage-file coverage.lcov
Coverage integration helps prioritize untested complex code.
Additional Tools
prodigy-validate-debtmap-improvement
Specialized validation tool for Prodigy workflow integration.
Description: This binary is part of the Prodigy workflow system and provides specialized validation for Debtmap improvement workflows.
Usage: See Prodigy documentation for detailed usage instructions.
See Also
- Configuration Format - Detailed configuration file format
- Output Formats - Understanding JSON, Markdown, and Terminal output
- Coverage Integration - Integrating test coverage data
- Context Providers - Understanding context-aware analysis
- Examples - More comprehensive usage examples
Analysis Guide
This guide explains Debtmap’s analysis capabilities, metrics, and methodologies in depth. Use this to understand what Debtmap measures, how it scores technical debt, and how to interpret analysis results for maximum impact.
Overview
Debtmap analyzes code through multiple lenses to provide a comprehensive view of technical health:
- Complexity Metrics - Quantifies how difficult code is to understand and test
- Debt Patterns - Identifies 13 types of technical debt requiring attention
- Risk Scoring - Correlates complexity with test coverage to find truly risky code
- Prioritization - Ranks findings by impact to guide refactoring efforts
The goal is to move beyond simple “here are your problems” to “here’s what to fix first and why.”
Complexity Metrics
Debtmap measures complexity using multiple complementary approaches. Each metric captures a different aspect of code difficulty.
Cyclomatic Complexity
Measures the number of linearly independent paths through code - essentially counting decision points.
How it works:
- Start with a base complexity of 1
- Add 1 for each:
if
,else if
,match
arm,while
,for
,&&
,||
,?
operator - Does NOT increase for
else
(it’s the alternate path, not a new decision)
Thresholds:
- 1-5: Simple, easy to test - typically needs 1-3 test cases
- 6-10: Moderate complexity - needs 4-8 test cases
- 11-20: Complex, consider refactoring - needs 9+ test cases
- 20+: Very complex, high risk - difficult to test thoroughly
Example:
#![allow(unused)] fn main() { fn validate_user(age: u32, has_license: bool, country: &str) -> bool { // Complexity: 4 // Base (1) + if (1) + && (1) + match (1) = 4 if age >= 18 && has_license { match country { "US" | "CA" => true, _ => false, } } else { false } } }
Cognitive Complexity
Measures how difficult code is to understand by considering nesting depth and control flow interruptions.
How it differs from cyclomatic:
- Nesting increases weight (deeply nested code is harder to understand)
- Linear sequences don’t increase complexity (easier to follow)
- Breaks and continues add complexity (interrupt normal flow)
Calculation:
- Each structure (if, loop, match) gets a base score
- Nesting multiplies the weight (nested structures = harder to understand)
- Break/continue/return in middle of function adds cognitive load
Example:
#![allow(unused)] fn main() { // Cyclomatic: 5, Cognitive: 8 fn process_items(items: Vec<Item>) -> Vec<Result> { let mut results = vec![]; for item in items { // +1 cognitive if item.is_valid() { // +2 (nested in loop) match item.type { // +3 (nested 2 levels) Type::A => results.push(process_a(item)), Type::B => { if item.priority > 5 { // +4 (nested 3 levels) results.push(process_b_priority(item)); } } _ => continue, // +1 (control flow interruption) } } } results } }
Thresholds:
- 0-5: Trivial - anyone can understand
- 6-10: Simple - straightforward logic
- 11-20: Moderate - requires careful reading
- 21-40: Complex - difficult to understand
- 40+: Very complex - needs refactoring
Entropy-Based Complexity Analysis
Uses information theory to distinguish genuinely complex code from pattern-based repetitive code. This dramatically reduces false positives for validation functions, dispatchers, and configuration parsers.
How it works:
-
Token Entropy (0.0-1.0): Measures variety in code tokens
- High entropy (0.7+): Diverse logic, genuinely complex
- Low entropy (0.0-0.4): Repetitive patterns, less complex than it appears
-
Pattern Repetition (0.0-1.0): Detects repetitive structures in AST
- High repetition (0.7+): Similar blocks repeated (validation checks, case handlers)
- Low repetition: Unique logic throughout
-
Branch Similarity (0.0-1.0): Analyzes similarity between conditional branches
- High similarity (0.8+): Branches do similar things (consistent handling)
- Low similarity: Each branch has unique logic
-
Token Classification: Categorizes tokens by type with weighted importance
- Variables, methods, literals weighted differently
- Focuses on structural complexity over superficial differences
Dampening logic: Dampening is applied when multiple factors indicate repetitive patterns:
- Low token entropy (< 0.4) indicates simple, repetitive patterns
- High pattern repetition (> 0.6) shows similar code blocks
- High branch similarity (> 0.7) indicates consistent branching logic
When these conditions are met:
effective_complexity = entropy × pattern_factor × similarity_factor
Dampening cap: The dampening factor has a minimum of 0.7, ensuring no more than 30% reduction in complexity scores. This prevents over-correction of pattern-based code and maintains a baseline complexity floor for functions that still require understanding and maintenance.
Example:
#![allow(unused)] fn main() { // Without entropy: Cyclomatic = 15 (appears very complex) // With entropy: Effective = 5 (pattern-based, dampened 67%) fn validate_config(config: &Config) -> Result<(), ValidationError> { if config.name.is_empty() { return Err(ValidationError::EmptyName); } if config.port == 0 { return Err(ValidationError::InvalidPort); } if config.host.is_empty() { return Err(ValidationError::EmptyHost); } if config.timeout == 0 { return Err(ValidationError::InvalidTimeout); } // ... 11 more similar checks Ok(()) } }
Enable in .debtmap.toml
:
[entropy]
enabled = true # Enable entropy analysis (default: true)
weight = 0.5 # Weight in adjustment (0.0-1.0)
use_classification = true # Advanced token classification
pattern_threshold = 0.7 # Pattern detection threshold
entropy_threshold = 0.4 # Entropy below this triggers dampening
branch_threshold = 0.8 # Branch similarity threshold
max_combined_reduction = 0.3 # Maximum 30% reduction
Output fields in EntropyScore:
unique_variables
: Count of distinct variables in the function (measures variable diversity)max_nesting
: Maximum nesting depth detected (contributes to dampening calculation)dampening_applied
: Actual dampening factor applied to the complexity score
Nesting Depth
Maximum level of indentation in a function. Deep nesting makes code hard to follow.
Thresholds:
- 1-2: Flat, easy to read
- 3-4: Moderate nesting
- 5+: Deep nesting, consider extracting functions
Example:
#![allow(unused)] fn main() { // Nesting depth: 4 (difficult to follow) fn process(data: Data) -> Result<Output> { if data.is_valid() { // Level 1 for item in data.items { // Level 2 if item.active { // Level 3 match item.type { // Level 4 Type::A => { /* ... */ } Type::B => { /* ... */ } } } } } } }
Refactored:
#![allow(unused)] fn main() { // Nesting depth: 2 (much clearer) fn process(data: Data) -> Result<Output> { if !data.is_valid() { return Err(Error::Invalid); } data.items .iter() .filter(|item| item.active) .map(|item| process_item(item)) // Extract to separate function .collect() } }
Function Length
Number of lines in a function. Long functions often violate single responsibility principle.
Thresholds:
- 1-20 lines: Good - focused, single purpose
- 21-50 lines: Acceptable - may have multiple steps
- 51-100 lines: Long - consider breaking up
- 100+ lines: Very long - definitely needs refactoring
Why length matters:
- Harder to understand and remember
- Harder to test thoroughly
- Often violates single responsibility
- Difficult to reuse
Debt Patterns
Debtmap detects 24 types of technical debt, organized into 4 strategic categories. Each debt type is mapped to a category that guides prioritization and remediation strategies.
Debt Type Enum
The DebtType
enum defines all specific debt patterns that Debtmap can detect:
Testing Debt:
TestingGap
- Functions with insufficient test coverageTestTodo
- TODO comments in test codeTestComplexity
- Test functions exceeding complexity thresholdsTestDuplication
- Duplicated code in test filesTestComplexityHotspot
- Complex test logic that’s hard to maintainAssertionComplexity
- Complex test assertionsFlakyTestPattern
- Non-deterministic test behavior
Architecture Debt:
ComplexityHotspot
- Functions exceeding complexity thresholdsDeadCode
- Unreachable or unused codeGodObject
- Classes with too many responsibilitiesGodModule
- Modules with too many responsibilitiesFeatureEnvy
- Using more data from other objects than ownPrimitiveObsession
- Overusing basic types instead of domain objectsMagicValues
- Unexplained literal values
Performance Debt:
AllocationInefficiency
- Inefficient memory allocationsStringConcatenation
- Inefficient string building in loopsNestedLoops
- Multiple nested iterations (O(n²) or worse)BlockingIO
- Blocking I/O in async contextsSuboptimalDataStructure
- Wrong data structure for access patternAsyncMisuse
- Improper async/await usageResourceLeak
- Resources not properly releasedCollectionInefficiency
- Inefficient collection operations
Code Quality Debt:
Risk
- High-risk code (complex + poorly tested)Duplication
- Duplicated code blocksErrorSwallowing
- Errors caught but ignored
Debt Categories
The DebtCategory
enum groups debt types into strategic categories:
#![allow(unused)] fn main() { pub enum DebtCategory { Architecture, // Structure, design, complexity Testing, // Coverage, test quality Performance, // Speed, memory, efficiency CodeQuality, // Maintainability, readability } }
Category Mapping:
Debt Type | Category | Strategic Focus |
---|---|---|
ComplexityHotspot, DeadCode, GodObject, GodModule, FeatureEnvy, PrimitiveObsession, MagicValues | Architecture | Structural improvements, design patterns |
TestingGap, TestTodo, TestComplexity, TestDuplication, TestComplexityHotspot, AssertionComplexity, FlakyTestPattern | Testing | Test coverage, test quality |
AllocationInefficiency, StringConcatenation, NestedLoops, BlockingIO, SuboptimalDataStructure, AsyncMisuse, ResourceLeak, CollectionInefficiency | Performance | Runtime efficiency, resource usage |
Risk, Duplication, ErrorSwallowing | CodeQuality | Maintainability, reliability |
Examples by Category
Architecture Debt
ComplexityHotspot: Functions exceeding complexity thresholds
#![allow(unused)] fn main() { // Cyclomatic: 22, Cognitive: 35 fn process_transaction(tx: Transaction, account: &mut Account) -> Result<Receipt> { if tx.amount <= 0 { return Err(Error::InvalidAmount); } // ... deeply nested logic with many branches Ok(receipt) } }
When detected: Cyclomatic > 10 OR Cognitive > 15 (configurable) Action: Break into smaller functions, extract validation, simplify control flow
GodObject / GodModule: Too many responsibilities
#![allow(unused)] fn main() { // God module: handles parsing, validation, storage, notifications mod user_service { fn parse_user() { /* ... */ } fn validate_user() { /* ... */ } fn save_user() { /* ... */ } fn send_email() { /* ... */ } fn log_activity() { /* ... */ } // ... 20+ more functions } }
When detected: Pattern analysis for responsibility clustering Action: Split into focused modules (parser, validator, repository, notifier)
MagicValues: Unexplained literals
#![allow(unused)] fn main() { // Bad: Magic numbers fn calculate_price(quantity: u32) -> f64 { quantity as f64 * 19.99 + 5.0 // What are these numbers? } // Good: Named constants const UNIT_PRICE: f64 = 19.99; const SHIPPING_COST: f64 = 5.0; fn calculate_price(quantity: u32) -> f64 { quantity as f64 * UNIT_PRICE + SHIPPING_COST } }
Testing Debt
TestingGap: Functions with insufficient test coverage
#![allow(unused)] fn main() { // 0% coverage - critical business logic untested fn calculate_tax(amount: f64, region: &str) -> f64 { // Complex tax calculation logic // No tests exist for this function! } }
When detected: Coverage data shows function has < 80% line coverage Action: Add unit tests to cover all branches and edge cases
TestComplexity: Test functions too complex
#![allow(unused)] fn main() { #[test] fn complex_test() { // Cyclomatic: 12 (too complex for a test) for input in test_cases { if input.is_special() { match input.type { /* complex test logic */ } } } } }
When detected: Test functions with cyclomatic > 10 or cognitive > 15 Action: Split into multiple focused tests, use test fixtures
FlakyTestPattern: Non-deterministic tests
#![allow(unused)] fn main() { #[test] fn flaky_test() { let result = async_operation().await; // Timing-dependent thread::sleep(Duration::from_millis(100)); // Race condition! assert_eq!(result.status, "complete"); } }
When detected: Pattern analysis for timing dependencies, random values Action: Use mocks, deterministic test data, proper async test utilities
Performance Debt
AllocationInefficiency: Excessive allocations
#![allow(unused)] fn main() { // Bad: Allocates on every iteration fn process_items(items: &[Item]) -> Vec<String> { let mut results = Vec::new(); for item in items { results.push(item.name.clone()); // Unnecessary clone } results } // Good: Pre-allocate, avoid clones fn process_items(items: &[Item]) -> Vec<&str> { items.iter().map(|item| item.name.as_str()).collect() } }
BlockingIO: Blocking operations in async contexts
#![allow(unused)] fn main() { // Bad: Blocks async runtime async fn load_data() -> Result<Data> { let file = std::fs::read_to_string("data.json")?; // Blocking! parse_json(&file) } // Good: Async I/O async fn load_data() -> Result<Data> { let file = tokio::fs::read_to_string("data.json").await?; parse_json(&file) } }
NestedLoops: O(n²) or worse complexity
#![allow(unused)] fn main() { // Bad: O(n²) nested loops fn find_duplicates(items: &[Item]) -> Vec<(Item, Item)> { let mut dupes = vec![]; for i in 0..items.len() { for j in i+1..items.len() { if items[i] == items[j] { dupes.push((items[i].clone(), items[j].clone())); } } } dupes } // Good: O(n) with HashSet fn find_duplicates(items: &[Item]) -> Vec<Item> { let mut seen = HashSet::new(); items.iter().filter(|item| !seen.insert(item)).cloned().collect() } }
Code Quality Debt
Duplication: Duplicated code blocks
#![allow(unused)] fn main() { // File A: fn process_user(user: User) -> Result<()> { validate_email(&user.email)?; validate_age(user.age)?; save_to_database(&user)?; send_welcome_email(&user.email)?; Ok(()) } // File B: Duplicated validation fn process_admin(admin: Admin) -> Result<()> { validate_email(&admin.email)?; // Duplicated validate_age(admin.age)?; // Duplicated save_to_database(&admin)?; grant_admin_privileges(&admin)?; Ok(()) } }
When detected: Similar code blocks > 50 lines (configurable) Action: Extract shared code into reusable functions
ErrorSwallowing: Errors caught but ignored
#![allow(unused)] fn main() { // Bad: Error swallowed, no context match risky_operation() { Ok(result) => process(result), Err(_) => {}, // Silent failure! } // Good: Error handled with context match risky_operation() { Ok(result) => process(result), Err(e) => { log::error!("Risky operation failed: {}", e); return Err(e.into()); } } }
When detected: Empty catch blocks, ignored Results Action: Add proper error logging and propagation
Risk: High-risk code (complex + poorly tested)
#![allow(unused)] fn main() { // Cyclomatic: 18, Coverage: 20%, Risk Score: 47.6 (HIGH) fn process_payment(tx: Transaction) -> Result<Receipt> { // Complex payment logic with minimal testing // High risk of bugs in production } }
When detected: Combines complexity metrics with coverage data Action: Either add comprehensive tests OR refactor to reduce complexity
Debt Scoring Formula
Each debt item gets a score based on priority and type:
debt_score = priority_weight × type_weight
Priority weights:
- Low = 1
- Medium = 3
- High = 5
- Critical = 10
Combined examples:
- Low Todo = 1 × 1 = 1
- Medium Fixme = 3 × 2 = 6
- High Complexity = 5 × 5 = 25
- Critical Complexity = 10 × 5 = 50
Total debt score = Sum of all debt item scores
Lower is better. Track over time to measure improvement.
Risk Scoring
Debtmap’s risk scoring identifies code that is both complex AND poorly tested - the true risk hotspots.
Unified Scoring System
Debtmap uses a unified scoring system (0-10 scale) as the primary prioritization mechanism. This multi-factor approach balances complexity, test coverage, and dependency impact, adjusted by function role.
Score Scale and Priority Classifications
Functions receive scores from 0 (minimal risk) to 10 (critical risk):
Score Range | Priority | Description | Action |
---|---|---|---|
9.0-10.0 | Critical | Severe risk requiring immediate attention | Address immediately |
7.0-8.9 | High | Significant risk, should be addressed soon | Plan for this sprint |
5.0-6.9 | Medium | Moderate risk, plan for future work | Schedule for next sprint |
3.0-4.9 | Low | Minor risk, lower priority | Monitor and address as time permits |
0.0-2.9 | Minimal | Well-managed code | Continue monitoring |
Scoring Formula
The unified score combines three weighted factors:
Base Score = (Complexity Factor × 0.40) + (Coverage Factor × 0.40) + (Dependency Factor × 0.20)
Final Score = Base Score × Role Multiplier
Factor Calculations:
Complexity Factor (0-10 scale):
Complexity Factor = min(10, ((cyclomatic / 10) + (cognitive / 20)) × 5)
Normalized to 0-10 range based on cyclomatic and cognitive complexity.
Coverage Factor (0-10 scale):
Coverage Factor = 10 × (1 - coverage_percentage) × complexity_weight
Uncovered complex code scores higher than uncovered simple code. Coverage dampens the score - well-tested code gets lower scores.
Dependency Factor (0-10 scale): Based on call graph analysis:
- High upstream caller count (many functions depend on this): 8-10
- On critical paths from entry points: 7-9
- Moderate dependencies: 4-6
- Isolated utilities: 1-3
Default Weights
The scoring formula uses configurable weights (default values shown):
- Complexity: 40% - How difficult the code is to understand and test
- Coverage: 40% - How well the code is tested
- Dependency: 20% - How many other functions depend on this code
These weights can be adjusted in .debtmap.toml
to match your team’s priorities.
Role-Based Prioritization
The unified score is multiplied by a role multiplier based on the function’s semantic classification:
Role | Multiplier | Description | Example |
---|---|---|---|
Entry Points | 1.5× | main(), HTTP handlers, API endpoints | User-facing code where bugs have immediate impact |
Business Logic | 1.2× | Core domain functions, algorithms | Critical functionality |
Data Access | 1.0× | Database queries, file I/O | Baseline importance |
Infrastructure | 0.8× | Logging, configuration, monitoring | Supporting code |
Utilities | 0.5× | Helpers, formatters, converters | Lower impact |
Test Code | 0.1× | Test functions, fixtures, mocks | Internal quality |
How role classification works:
Debtmap identifies function roles through pattern analysis:
- Entry points: Functions named
main
, handlers with routing decorators, public API functions - Business logic: Core domain operations, calculation functions, decision-making code
- Data access: Database queries, file operations, network calls
- Infrastructure: Logging, config parsing, monitoring, error handling
- Utilities: Helper functions, formatters, type converters, validators
- Test code: Functions in test modules, test functions, fixtures
Example: Same complexity, different priorities
Consider a function with base score 8.0:
If classified as Entry Point:
Final Score = 8.0 × 1.5 = 12.0 (capped at 10.0) → CRITICAL priority
If classified as Business Logic:
Final Score = 8.0 × 1.2 = 9.6 → CRITICAL priority
If classified as Data Access:
Final Score = 8.0 × 1.0 = 8.0 → HIGH priority
If classified as Utility:
Final Score = 8.0 × 0.5 = 4.0 → LOW priority
This ensures that complex code in critical paths gets higher priority than equally complex utility code.
Coverage Propagation
Coverage impact flows through the call graph using transitive coverage:
Transitive Coverage = Direct Coverage + Σ(Caller Coverage × Weight)
How it works:
Functions called by well-tested code inherit some coverage benefit, reducing their urgency. This helps identify which untested functions are on critical paths versus safely isolated utilities.
Example scenarios:
Scenario 1: Untested function with well-tested callers
Function A: 0% direct coverage
Called by:
- handle_request (95% coverage)
- process_payment (90% coverage)
- validate_order (88% coverage)
Transitive coverage: ~40% (inherits coverage benefit from callers)
Final priority: Lower than isolated 0% coverage function
Scenario 2: Untested function on critical path
Function B: 0% direct coverage
Called by:
- main (0% coverage)
- startup (10% coverage)
Transitive coverage: ~5% (minimal coverage benefit)
Final priority: Higher - on critical path with no safety net
Coverage propagation prevents false alarms about utility functions called only by well-tested code, while highlighting genuinely risky untested code on critical paths.
Unified Score Example
Function: process_payment
Location: src/payments.rs:145
Metrics:
- Cyclomatic complexity: 18
- Cognitive complexity: 25
- Test coverage: 20%
- Upstream callers: 3 (high dependency)
- Role: Business Logic
Calculation:
Complexity Factor = min(10, ((18/10) + (25/20)) × 5) = min(10, 8.75) = 8.75
Coverage Factor = 10 × (1 - 0.20) × 1.0 = 8.0
Dependency Factor = 7.5 (3 upstream callers, moderate impact)
Base Score = (8.75 × 0.40) + (8.0 × 0.40) + (7.5 × 0.20)
= 3.5 + 3.2 + 1.5
= 8.2
Final Score = 8.2 × 1.2 (Business Logic multiplier)
= 9.84 → CRITICAL priority
Legacy Risk Scoring (Pre-0.2.x)
Prior to the unified scoring system, Debtmap used a simpler additive risk formula. This is still available for compatibility but unified scoring is now the default and provides better prioritization.
Risk Categories
Note: The RiskLevel
enum (Low, Medium, High, Critical) is used for legacy risk scoring compatibility. When using unified scoring (0-10 scale), refer to the priority classifications shown in the Unified Scoring System section above.
Legacy RiskLevel Enum
For legacy risk scoring, Debtmap classifies functions into four risk levels:
#![allow(unused)] fn main() { pub enum RiskLevel { Low, // Score < 10 Medium, // Score 10-24 High, // Score 25-49 Critical, // Score ≥ 50 } }
Critical (legacy score ≥ 50)
- High complexity (cyclomatic > 15) AND low coverage (< 30%)
- Untested code that’s likely to break and hard to fix
- Action: Immediate attention required - add tests or refactor
High (legacy score 25-49)
- High complexity (cyclomatic > 10) AND moderate coverage (< 60%)
- Risky code with incomplete testing
- Action: Should be addressed soon
Medium (legacy score 10-24)
- Moderate complexity (cyclomatic > 5) AND low coverage (< 50%)
- OR: High complexity with good coverage
- Action: Plan for next sprint
Low (legacy score < 10)
- Low complexity OR high coverage
- Well-managed code
- Action: Monitor, low priority
Unified Scoring Priority Levels
When using unified scoring (default), functions are classified using the 0-10 scale:
- Critical (9.0-10.0): Immediate attention
- High (7.0-8.9): Address this sprint
- Medium (5.0-6.9): Plan for next sprint
- Low (3.0-4.9): Monitor and address as time permits
- Minimal (0.0-2.9): Well-managed code
Well-tested complex code is an outcome in both systems, not a separate category:
- Complex function (cyclomatic 18, cognitive 25) with 95% coverage
- Unified score: ~2.5 (Minimal priority due to coverage dampening)
- Legacy risk score: ~8 (Low risk)
- Falls into low-priority categories because good testing mitigates complexity
- This is the desired state for inherently complex business logic
Legacy Risk Calculation
Note: The legacy risk calculation is still supported for compatibility but has been superseded by the unified scoring system (see above). Unified scoring provides better prioritization through its multi-factor, weighted approach with role-based adjustments.
The legacy risk score uses a simpler additive formula:
#![allow(unused)] fn main() { risk_score = complexity_factor + coverage_factor + debt_factor where: complexity_factor = (cyclomatic / 5) + (cognitive / 10) coverage_factor = (1 - coverage_percentage) × 50 debt_factor = debt_score / 10 // If debt data available }
Example (legacy scoring):
Function: process_payment
- Cyclomatic complexity: 18
- Cognitive complexity: 25
- Coverage: 20%
- Debt score: 15
Calculation:
complexity_factor = (18 / 5) + (25 / 10) = 3.6 + 2.5 = 6.1
coverage_factor = (1 - 0.20) × 50 = 40
debt_factor = 15 / 10 = 1.5
risk_score = 6.1 + 40 + 1.5 = 47.6 (HIGH RISK)
When to use legacy scoring:
- Comparing with historical data from older Debtmap versions
- Teams with existing workflows built around the old scale
- Gradual migration to unified scoring
Why unified scoring is better:
- Normalized 0-10 scale is more intuitive
- Weighted factors (40% complexity, 40% coverage, 20% dependency) provide better balance
- Role multipliers adjust priority based on function importance
- Coverage propagation reduces false positives for utility functions
Test Effort Assessment
Debtmap estimates testing difficulty based on cognitive complexity:
Difficulty Levels:
- Trivial (cognitive < 5): 1-2 test cases, < 1 hour
- Simple (cognitive 5-10): 3-5 test cases, 1-2 hours
- Moderate (cognitive 10-20): 6-10 test cases, 2-4 hours
- Complex (cognitive 20-40): 11-20 test cases, 4-8 hours
- VeryComplex (cognitive > 40): 20+ test cases, 8+ hours
Test Effort includes:
- Cognitive load: How hard to understand the function
- Branch count: Number of paths to test
- Recommended test cases: Suggested number of tests
Risk Distribution
Debtmap provides codebase-wide risk metrics:
{
"risk_distribution": {
"critical_count": 12,
"high_count": 45,
"medium_count": 123,
"low_count": 456,
"minimal_count": 234,
"total_functions": 870
},
"codebase_risk_score": 1247.5
}
Interpreting distribution:
- Healthy codebase: Most functions in Low/Minimal priority (unified scoring) or Low/WellTested (legacy)
- Needs attention: Many Critical/High priority functions
- Technical debt: High codebase risk score
Note on well-tested functions:
In unified scoring, well-tested complex code simply scores low (0-2.9 Minimal or 3-4.9 Low) due to coverage dampening - it’s not a separate category. The minimal_count
in the distribution represents functions with unified scores 0-2.9, which includes well-tested complex code.
Testing Recommendations
When coverage data is provided, Debtmap generates prioritized testing recommendations with ROI analysis:
{
"function": "process_transaction",
"file": "src/payments.rs",
"line": 145,
"current_risk": 47.6,
"potential_risk_reduction": 35.2,
"test_effort_estimate": {
"estimated_difficulty": "Complex",
"cognitive_load": 25,
"branch_count": 18,
"recommended_test_cases": 12
},
"roi": 4.4,
"rationale": "High complexity with low coverage (20%) and 3 downstream dependencies. Testing will reduce risk by 74%.",
"dependencies": {
"upstream_callers": ["handle_payment_request"],
"downstream_callees": ["validate_amount", "check_balance", "record_transaction"]
}
}
ROI calculation:
roi = potential_risk_reduction / estimated_effort_hours
Higher ROI = better return on testing investment
Interpreting Results
Understanding Output Formats
Debtmap provides three output formats:
Terminal (default): Human-readable with colors and tables
debtmap analyze .
JSON: Machine-readable for CI/CD integration
debtmap analyze . --format json --output report.json
Markdown: Documentation-friendly
debtmap analyze . --format markdown --output report.md
JSON Structure
{
"timestamp": "2025-10-09T12:00:00Z",
"project_path": "/path/to/project",
"complexity": {
"metrics": [
{
"name": "process_data",
"file": "src/main.rs",
"line": 42,
"cyclomatic": 15,
"cognitive": 22,
"nesting": 4,
"length": 68,
"is_test": false,
"visibility": "Public",
"is_trait_method": false,
"in_test_module": false,
"entropy_score": {
"token_entropy": 0.65,
"pattern_repetition": 0.25,
"branch_similarity": 0.30,
"effective_complexity": 0.85
},
"is_pure": false,
"purity_confidence": 0.8,
"detected_patterns": ["validation_pattern"],
"upstream_callers": ["main", "process_request"],
"downstream_callees": ["validate", "save", "notify"]
}
],
"summary": {
"total_functions": 150,
"average_complexity": 5.3,
"max_complexity": 22,
"high_complexity_count": 8
}
},
"technical_debt": {
"items": [
{
"id": "complexity_src_main_rs_42",
"debt_type": "Complexity",
"priority": "High",
"file": "src/main.rs",
"line": 42,
"column": 1,
"message": "Function exceeds complexity threshold",
"context": "Cyclomatic: 15, Cognitive: 22"
}
],
"by_type": {
"Complexity": [...],
"Duplication": [...],
"Todo": [...]
}
}
}
Reading Function Metrics
Key fields:
cyclomatic
: Decision points - guides test case countcognitive
: Understanding difficulty - guides refactoring prioritynesting
: Indentation depth - signals need for extractionlength
: Lines of code - signals SRP violationsvisibility
: Function visibility ("Private"
,"Crate"
, or"Public"
from FunctionVisibility enum)is_pure
: No side effects - easier to test (Option type, may be None)purity_confidence
: How certain we are about purity 0.0-1.0 (Option type, may be None)is_trait_method
: Whether this function implements a trait methodin_test_module
: Whether function is inside a#[cfg(test)]
moduledetected_patterns
: Complexity adjustment patterns identified (e.g., “validation_pattern”)entropy_score
: Pattern analysis for false positive reductionupstream_callers
: Impact radius if this function breaksdownstream_callees
: Functions this depends on
Entropy interpretation:
token_entropy < 0.4
: Repetitive code, likely pattern-basedpattern_repetition > 0.7
: High similarity between blocksbranch_similarity > 0.8
: Similar conditional brancheseffective_complexity < 1.0
: Dampening applied
Prioritizing Work
Debtmap provides multiple prioritization strategies, with unified scoring (0-10 scale) as the recommended default for most workflows:
1. By Unified Score (default - recommended)
debtmap analyze . --top 10
Shows top 10 items by combined complexity, coverage, and dependency factors, weighted and adjusted by function role.
Why use unified scoring:
- Balances complexity (40%), coverage (40%), and dependency impact (20%)
- Adjusts for function importance (entry points prioritized over utilities)
- Normalized 0-10 scale is intuitive and consistent
- Reduces false positives through coverage propagation
- Best for sprint planning and function-level refactoring decisions
Example:
# Show top 20 critical items
debtmap analyze . --min-priority 7.0 --top 20
# Focus on high-impact functions (score >= 7.0)
debtmap analyze . --format json | jq '.functions[] | select(.unified_score >= 7.0)'
2. By Risk Category (legacy compatibility)
debtmap analyze . --min-priority high
Shows only HIGH and CRITICAL priority items using legacy risk scoring.
Note: Legacy risk scoring uses additive formulas and unbounded scales. Prefer unified scoring for new workflows.
3. By Debt Type
debtmap analyze . --filter Architecture,Testing
Focuses on specific categories:
Architecture
: God objects, complexity, dead codeTesting
: Coverage gaps, test qualityPerformance
: Resource leaks, inefficienciesCodeQuality
: Code smells, maintainability
4. By ROI (with coverage)
debtmap analyze . --lcov coverage.lcov --top 20
Prioritizes by return on investment for testing/refactoring. Combines unified scoring with test effort estimates to identify high-value work.
Choosing the right strategy:
- Sprint planning for developers: Use unified scoring (
--top N
) - Architectural review: Use tiered prioritization (
--summary
) - Category-focused work: Use debt type filtering (
--filter
) - Testing priorities: Use ROI analysis with coverage data (
--lcov
) - Historical comparisons: Use legacy risk scoring (for consistency with old reports)
Tiered Prioritization
Note: Tiered prioritization uses traditional debt scoring (additive, higher = worse) and is complementary to the unified scoring system (0-10 scale). Both systems can be used together:
- Unified scoring (0-10 scale): Best for function-level prioritization and sprint planning
- Tiered prioritization (debt tiers): Best for architectural focus and strategic debt planning
Use --summary
for tiered view focusing on architectural issues, or default output for function-level unified scores.
Debtmap uses a tier-based system to map debt scores to actionable priority levels. Each tier includes effort estimates and strategic guidance for efficient debt remediation.
Tier Levels
The Tier
enum defines four priority levels based on score thresholds:
#![allow(unused)] fn main() { pub enum Tier { Critical, // Score ≥ 90 High, // Score 70-89.9 Moderate, // Score 50-69.9 Low, // Score < 50 } }
Score-to-Tier Mapping:
- Critical (≥ 90): Immediate action required - blocks progress
- High (70-89.9): Should be addressed this sprint
- Moderate (50-69.9): Plan for next sprint
- Low (< 50): Background maintenance work
Effort Estimates Per Tier
Each tier includes estimated effort based on typical remediation patterns:
Tier | Estimated Effort | Typical Work |
---|---|---|
Critical | 1-2 days | Major refactoring, comprehensive testing, architectural changes |
High | 2-4 hours | Extract functions, add test coverage, fix resource leaks |
Moderate | 1-2 hours | Simplify logic, reduce duplication, improve error handling |
Low | 30 minutes | Address TODOs, minor cleanup, documentation |
Effort calculation considers:
- Complexity metrics (cyclomatic, cognitive)
- Test coverage gaps
- Number of dependencies (upstream/downstream)
- Debt category (Architecture debt takes longer than CodeQuality)
Tiered Display Grouping
TieredDisplay
groups similar debt items for batch action recommendations:
#![allow(unused)] fn main() { pub struct TieredDisplay { pub tier: Tier, pub items: Vec<DebtItem>, pub total_score: f64, pub estimated_total_effort_hours: f64, pub batch_recommendations: Vec<String>, } }
Grouping strategy:
- Groups items by tier and similarity pattern
- Prevents grouping of god objects (always show individually)
- Prevents grouping of Critical items (each needs individual attention)
- Suggests batch actions for similar Low/Moderate items
Example batch recommendations:
{
"tier": "Moderate",
"total_score": 245.8,
"estimated_total_effort_hours": 12.5,
"batch_recommendations": [
"Extract 5 validation functions from similar patterns",
"Add test coverage for 8 moderately complex functions (grouped by module)",
"Refactor 3 functions with similar nested loop patterns"
]
}
Using Tiered Prioritization
1. Start with Critical tier:
debtmap analyze . --min-priority critical
Focus on items with score ≥ 90. These typically represent:
- Complex functions with 0% coverage
- God objects blocking feature development
- Critical resource leaks or security issues
2. Plan High tier work:
debtmap analyze . --min-priority high --format json > sprint-plan.json
Schedule 2-4 hours per item for this sprint. Look for:
- Functions approaching complexity thresholds
- Moderate coverage gaps on important code paths
- Performance bottlenecks with clear solutions
3. Batch Moderate tier items:
debtmap analyze . --min-priority moderate
Review batch recommendations. Examples:
- “10 validation functions detected - extract common pattern”
- “5 similar test files with duplication - create shared fixtures”
- “8 functions with magic values - create constants module”
4. Schedule Low tier background work: Address during slack time or as warm-up tasks for new contributors.
Strategic Guidance by Tier
Critical Tier Strategy:
- Block new features until addressed
- Pair programming recommended for complex items
- Architectural review before major refactoring
- Comprehensive testing after changes
High Tier Strategy:
- Sprint planning priority
- Impact analysis before changes
- Code review from senior developers
- Integration testing after changes
Moderate Tier Strategy:
- Batch similar items for efficiency
- Extract patterns across multiple files
- Incremental improvement over multiple PRs
- Regression testing for affected areas
Low Tier Strategy:
- Good first issues for new contributors
- Documentation improvements
- Code cleanup during refactoring nearby code
- Technical debt gardening sessions
Categorized Debt Analysis
Debtmap provides CategorizedDebt
analysis that groups debt items by category and identifies cross-category dependencies. This helps teams understand strategic relationships between different types of technical debt.
CategorySummary
Each category gets a summary with metrics for planning:
#![allow(unused)] fn main() { pub struct CategorySummary { pub category: DebtCategory, pub total_score: f64, pub item_count: usize, pub estimated_effort_hours: f64, pub average_severity: f64, pub top_items: Vec<DebtItem>, // Up to 5 highest priority } }
Effort estimation formulas:
- Architecture debt:
complexity_score / 10 × 2
hours (structural changes take longer) - Testing debt:
complexity_score / 10 × 1.5
hours (writing tests) - Performance debt:
complexity_score / 10 × 1.8
hours (profiling + optimization) - CodeQuality debt:
complexity_score / 10 × 1.2
hours (refactoring)
Example category summary:
{
"category": "Architecture",
"total_score": 487.5,
"item_count": 15,
"estimated_effort_hours": 97.5,
"average_severity": 32.5,
"top_items": [
{
"debt_type": "GodObject",
"file": "src/services/user_service.rs",
"score": 95.0,
"estimated_effort_hours": 16.0
},
{
"debt_type": "ComplexityHotspot",
"file": "src/payments/processor.rs",
"score": 87.3,
"estimated_effort_hours": 14.0
}
]
}
Cross-Category Dependencies
CrossCategoryDependency
identifies blocking relationships between different debt categories:
#![allow(unused)] fn main() { pub struct CrossCategoryDependency { pub from_category: DebtCategory, pub to_category: DebtCategory, pub blocking_items: Vec<(DebtItem, DebtItem)>, pub impact_level: ImpactLevel, // Critical, High, Medium, Low pub recommendation: String, } }
Common dependency patterns:
1. Architecture blocks Testing:
- Pattern: God objects are too complex to test effectively
- Example:
UserService
has 50+ functions, making comprehensive testing impractical - Impact: Critical - cannot improve test coverage without refactoring
- Recommendation: “Split god object into 4-5 focused modules before adding tests”
2. Async issues require Architecture changes:
- Pattern: Blocking I/O in async contexts requires architectural redesign
- Example: Sync database calls in async handlers
- Impact: High - performance problems require design changes
- Recommendation: “Introduce async database layer before optimizing handlers”
3. Complexity affects Testability:
- Pattern: High cyclomatic complexity makes thorough testing difficult
- Example: Function with 22 branches needs 22+ test cases
- Impact: High - testing effort grows exponentially with complexity
- Recommendation: “Reduce complexity to < 10 before writing comprehensive tests”
4. Performance requires Architecture:
- Pattern: O(n²) nested loops need different data structures
- Example: Linear search in loops should use HashMap
- Impact: Medium - optimization requires structural changes
- Recommendation: “Refactor data structure before micro-optimizations”
Example cross-category dependency:
{
"from_category": "Architecture",
"to_category": "Testing",
"impact_level": "Critical",
"blocking_items": [
{
"blocker": {
"debt_type": "GodObject",
"file": "src/services/user_service.rs",
"functions": 52,
"score": 95.0
},
"blocked": {
"debt_type": "TestingGap",
"file": "src/services/user_service.rs",
"coverage": 15,
"score": 78.0
}
}
],
"recommendation": "Split UserService into focused modules (auth, profile, settings, notifications) before attempting to improve test coverage. Current structure makes comprehensive testing impractical.",
"estimated_unblock_effort_hours": 16.0
}
Using Categorized Debt Analysis
View all category summaries:
debtmap analyze . --format json | jq '.categorized_debt.summaries'
Focus on specific category:
debtmap analyze . --filter Architecture --top 10
Identify blocking relationships:
debtmap analyze . --format json | jq '.categorized_debt.cross_category_dependencies[] | select(.impact_level == "Critical")'
Strategic planning workflow:
-
Review category summaries:
- Identify which category has highest total score
- Check estimated effort hours per category
- Note average severity to gauge urgency
-
Check cross-category dependencies:
- Find Critical and High impact blockers
- Prioritize blockers before blocked items
- Plan architectural changes before optimization
-
Plan remediation order:
Example decision tree: - Architecture score > 400? → Address god objects first - Testing gap with low complexity? → Quick wins, add tests - Performance issues + architecture debt? → Refactor structure first - High code quality debt but good architecture? → Incremental cleanup
-
Use category-specific strategies:
- Architecture: Pair programming, design reviews, incremental refactoring
- Testing: TDD for new code, characterization tests for legacy
- Performance: Profiling first, optimize hot paths, avoid premature optimization
- CodeQuality: Code review focus, linting rules, consistent patterns
CategorizedDebt Output Structure
{
"categorized_debt": {
"summaries": [
{
"category": "Architecture",
"total_score": 487.5,
"item_count": 15,
"estimated_effort_hours": 97.5,
"average_severity": 32.5,
"top_items": [...]
},
{
"category": "Testing",
"total_score": 356.2,
"item_count": 23,
"estimated_effort_hours": 53.4,
"average_severity": 15.5,
"top_items": [...]
},
{
"category": "Performance",
"total_score": 234.8,
"item_count": 12,
"estimated_effort_hours": 42.3,
"average_severity": 19.6,
"top_items": [...]
},
{
"category": "CodeQuality",
"total_score": 189.3,
"item_count": 31,
"estimated_effort_hours": 22.7,
"average_severity": 6.1,
"top_items": [...]
}
],
"cross_category_dependencies": [
{
"from_category": "Architecture",
"to_category": "Testing",
"impact_level": "Critical",
"blocking_items": [...],
"recommendation": "..."
}
]
}
}
Debt Density Metric
Debt density normalizes technical debt scores across projects of different sizes, providing a per-1000-lines-of-code metric for fair comparison.
Formula
debt_density = (total_debt_score / total_lines_of_code) × 1000
Example calculation:
Project A:
- Total debt score: 1,250
- Total lines of code: 25,000
- Debt density: (1,250 / 25,000) × 1000 = 50
Project B:
- Total debt score: 2,500
- Total lines of code: 50,000
- Debt density: (2,500 / 50,000) × 1000 = 50
Projects A and B have equal debt density (50) despite B having twice the absolute debt, because B is also twice as large. They have proportionally similar technical debt.
Interpretation Guidelines
Use these thresholds to assess codebase health:
Debt Density | Assessment | Description |
---|---|---|
0-50 | Clean | Well-maintained codebase, minimal debt |
51-100 | Moderate | Typical technical debt, manageable |
101-150 | High | Significant debt, prioritize remediation |
150+ | Critical | Severe debt burden, may impede development |
Context matters:
- Early-stage projects: Often have higher density (rapid iteration)
- Mature projects: Should trend toward lower density over time
- Legacy systems: May have high density, track trend over time
- Greenfield rewrites: Aim for density < 50
Using Debt Density
1. Compare projects fairly:
# Small microservice (5,000 LOC, debt = 250)
# Debt density: 50
# Large monolith (100,000 LOC, debt = 5,000)
# Debt density: 50
# Equal health despite size difference
2. Track improvement over time:
Sprint 1: 50,000 LOC, debt = 7,500, density = 150 (High)
Sprint 5: 52,000 LOC, debt = 6,500, density = 125 (Improving)
Sprint 10: 54,000 LOC, debt = 4,860, density = 90 (Moderate)
3. Set team goals:
Current density: 120
Target density: < 80 (by Q4)
Reduction needed: 40 points
Strategy:
- Fix 2-3 Critical items per sprint
- Prevent new debt (enforce thresholds)
- Refactor before adding features in high-debt modules
4. Benchmark across teams/projects:
{
"team_metrics": [
{
"project": "auth-service",
"debt_density": 45,
"assessment": "Clean",
"trend": "stable"
},
{
"project": "billing-service",
"debt_density": 95,
"assessment": "Moderate",
"trend": "improving"
},
{
"project": "legacy-api",
"debt_density": 165,
"assessment": "Critical",
"trend": "worsening"
}
]
}
Limitations
Debt density doesn’t account for:
- Code importance: 100 LOC in payment logic ≠ 100 LOC in logging utils
- Complexity distribution: One 1000-line god object vs. 1000 simple functions
- Test coverage: 50% coverage on critical paths vs. low-priority features
- Team familiarity: New codebase vs. well-understood legacy system
Best practices:
- Use density as one metric among many
- Combine with category analysis and tiered prioritization
- Focus on trend (improving/stable/worsening) over absolute number
- Consider debt per module for more granular insights
Debt Density in CI/CD
Track density over time:
# Generate report with density
debtmap analyze . --format json --output debt-report.json
# Extract density for trending
DENSITY=$(jq '.debt_density' debt-report.json)
# Store in metrics database
echo "debtmap.density:${DENSITY}|g" | nc -u -w0 statsd 8125
Set threshold gates:
# .github/workflows/debt-check.yml
- name: Check debt density
run: |
DENSITY=$(debtmap analyze . --format json | jq '.debt_density')
if (( $(echo "$DENSITY > 150" | bc -l) )); then
echo "❌ Debt density too high: $DENSITY (limit: 150)"
exit 1
fi
echo "✅ Debt density acceptable: $DENSITY"
Actionable Insights
Each recommendation includes:
ACTION: What to do
- “Add 6 unit tests for full coverage”
- “Refactor into 3 smaller functions”
- “Extract validation to separate function”
IMPACT: Expected improvement
- “Full test coverage, -3.7 risk”
- “Reduce complexity from 22 to 8”
- “Eliminate 120 lines of duplication”
WHY: Rationale
- “Business logic with 0% coverage, manageable complexity”
- “High complexity with low coverage threatens stability”
- “Repeated validation pattern across 5 files”
Example workflow:
- Run analysis with coverage:
debtmap analyze . --lcov coverage.lcov
- Filter to CRITICAL items:
--min-priority critical
- Review top 5 recommendations
- Start with highest ROI items
- Rerun analysis to track progress
Common Patterns to Recognize
Pattern 1: High Complexity, Well Tested
Complexity: 25, Coverage: 95%, Risk: LOW
This is actually good! Complex but thoroughly tested code. Learn from this approach.
Pattern 2: Moderate Complexity, No Tests
Complexity: 12, Coverage: 0%, Risk: CRITICAL
Highest priority - manageable complexity, should be easy to test.
Pattern 3: Low Complexity, No Tests
Complexity: 3, Coverage: 0%, Risk: LOW
Low priority - simple code, less risky without tests.
Pattern 4: Repetitive High Complexity (Dampened)
Cyclomatic: 20, Effective: 7 (65% dampened), Risk: LOW
Validation or dispatch pattern - looks complex but is repetitive. Lower priority.
Pattern 5: God Object
File: services.rs, Functions: 50+, Responsibilities: 15+
Architectural issue - split before adding features.
Analyzer Types
Debtmap supports multiple programming languages with varying levels of analysis capability.
Supported Languages
Rust (Full Support)
- Parser: syn (native Rust AST)
- Capabilities:
- Full complexity metrics (cyclomatic, cognitive, entropy)
- Trait implementation tracking
- Purity detection with confidence scoring
- Call graph analysis (upstream callers, downstream callees)
- Semantic function classification (entry points, business logic, data access, infrastructure, utilities, test code)
- Enhanced call graph with transitive relationships
- Macro expansion support for accurate complexity analysis
- Pattern-based adjustments for macros and code generation
- Visibility tracking (pub, pub(crate), private)
- Test module detection (#[cfg(test)])
Semantic Classification:
Debtmap automatically identifies function roles in Rust code to apply appropriate role multipliers in unified scoring:
- Entry Points: Functions named
main
,start
, or public functions inbin/
modules - Business Logic: Core domain functions with complex logic, algorithms, business rules
- Data Access: Functions performing database queries, file I/O, network operations
- Infrastructure: Logging, configuration, monitoring, error handling utilities
- Utilities: Helper functions, formatters, type converters, validation functions
- Test Code: Functions in
#[cfg(test)]
modules, functions with#[test]
attribute
This classification feeds directly into the unified scoring system’s role multiplier (see Risk Scoring section).
Python (Partial Support)
- Parser: rustpython-parser
- Capabilities:
- Complexity metrics (cyclomatic, cognitive)
- Python-specific error handling patterns
- Purity detection for pure functions
- Basic debt pattern detection
- Limited call graph support
JavaScript (Partial Support)
- Parser: tree-sitter (JavaScript grammar)
- File extensions: .js, .jsx, .mjs, .cjs
- Capabilities:
- ECMAScript complexity patterns
- Basic complexity metrics
- Function extraction
- Limited pattern detection
TypeScript (Partial Support)
- Parser: tree-sitter (TypeScript grammar)
- File extensions: .ts, .tsx, .mts, .cts
- Capabilities:
- Similar to JavaScript support
- Type information currently not utilized
- Basic complexity metrics
- Limited pattern detection
Unsupported Languages:
Debtmap’s Language
enum contains only the four supported languages: Rust, Python, JavaScript, and TypeScript. Files with unsupported extensions are filtered out during the file discovery phase and never reach the analysis stage.
File filtering behavior:
- Discovery scans project for files matching supported extensions
- Unsupported files (
.cpp
,.java
,.go
, etc.) are skipped silently - No analysis, metrics, or debt patterns are generated for filtered files
- Use
--languages
flag to explicitly control which languages to analyze
Example:
# Only analyze Rust files (skip Python/JS/TS)
debtmap analyze . --languages rust
# Analyze Rust and Python only
debtmap analyze . --languages rust,python
Language Detection
Automatic detection by file extension:
#![allow(unused)] fn main() { let language = Language::from_path(&path); }
Explicit language selection:
debtmap analyze . --languages rust,python
Extensibility
Debtmap’s architecture allows adding new languages:
- Implement Analyzer trait:
#![allow(unused)] fn main() { pub trait Analyzer: Send + Sync { fn parse(&self, content: &str, path: PathBuf) -> Result<Ast>; fn analyze(&self, ast: &Ast) -> FileMetrics; fn language(&self) -> Language; } }
- Register in get_analyzer():
#![allow(unused)] fn main() { pub fn get_analyzer(language: Language) -> Box<dyn Analyzer> { match language { Language::Rust => Box::new(RustAnalyzer::new()), Language::YourLanguage => Box::new(YourAnalyzer::new()), // ... } } }
See src/analyzers/rust.rs
for a complete implementation example.
Advanced Features
Purity Detection
Debtmap detects pure functions - those without side effects that always return the same output for the same input.
What makes a function pure:
- No I/O operations (file, network, database)
- No mutable global state
- No random number generation
- No system calls
- Deterministic output
Purity detection is optional:
- Both
is_pure
andpurity_confidence
areOption
types - May be
None
for some functions or languages where detection is not available - Rust has the most comprehensive purity detection support
Confidence scoring (when available):
- 0.9-1.0: Very confident (no side effects detected)
- 0.7-0.8: Likely pure (minimal suspicious patterns)
- 0.5-0.6: Uncertain (some suspicious patterns)
- 0.0-0.4: Likely impure (side effects detected)
Example:
#![allow(unused)] fn main() { // Pure: confidence = 0.95 fn calculate_total(items: &[Item]) -> f64 { items.iter().map(|i| i.price).sum() } // Impure: confidence = 0.1 (I/O detected) fn save_total(items: &[Item]) -> Result<()> { let total = items.iter().map(|i| i.price).sum(); write_to_file(total) // Side effect! } }
Benefits:
- Pure functions are easier to test
- Can be safely cached or memoized
- Safe to parallelize
- Easier to reason about
Data Flow Analysis
Debtmap builds a comprehensive DataFlowGraph
that extends basic call graph analysis with variable dependencies, data transformations, I/O operations, and purity tracking.
Call Graph Foundation
Upstream callers - Who calls this function
- Indicates impact radius
- More callers = higher impact if it breaks
Downstream callees - What this function calls
- Indicates dependencies
- More callees = more integration testing needed
Example:
{
"name": "process_payment",
"upstream_callers": [
"handle_checkout",
"process_subscription",
"handle_refund"
],
"downstream_callees": [
"validate_payment_method",
"calculate_fees",
"record_transaction",
"send_receipt"
]
}
Variable Dependency Tracking
DataFlowGraph
tracks which variables each function depends on:
#![allow(unused)] fn main() { pub struct DataFlowGraph { // Maps function_id -> set of variable names used variable_dependencies: HashMap<String, HashSet<String>>, // ... } }
What it tracks:
- Local variables accessed in function body
- Function parameters
- Captured variables (closures)
- Mutable vs immutable references
Benefits:
- Identify functions coupled through shared state
- Detect potential side effect chains
- Guide refactoring to reduce coupling
Example output:
{
"function": "calculate_total",
"variable_dependencies": ["items", "tax_rate", "discount", "total"],
"parameter_count": 3,
"local_var_count": 1
}
Data Transformation Patterns
DataFlowGraph
identifies common functional programming patterns:
#![allow(unused)] fn main() { pub enum TransformationType { Map, // Transform each element Filter, // Select subset of elements Reduce, // Aggregate to single value FlatMap, // Transform and flatten Unknown, // Other transformations } }
Pattern detection:
- Recognizes iterator chains (
.map()
,.filter()
,.fold()
) - Identifies functional vs imperative data flow
- Tracks input/output variable relationships
Example:
#![allow(unused)] fn main() { // Detected as: Filter → Map → Reduce pattern fn total_active_users(users: &[User]) -> f64 { users.iter() .filter(|u| u.active) // Filter transformation .map(|u| u.balance) // Map transformation .sum() // Reduce transformation } }
Transformation metadata:
{
"function": "total_active_users",
"input_vars": ["users"],
"output_vars": ["sum_result"],
"transformation_type": "Reduce",
"is_functional_style": true,
"pipeline_length": 3
}
I/O Operation Detection
Tracks functions performing I/O operations for purity and performance analysis:
I/O categories tracked:
- File I/O:
std::fs
,File::open
,read_to_string
- Network I/O: HTTP requests, socket operations
- Database I/O: SQL queries, ORM operations
- System calls: Process spawning, environment access
- Blocking operations:
thread::sleep
, synchronous I/O in async
Example detection:
#![allow(unused)] fn main() { // Detected I/O operations: FileRead, FileWrite fn save_config(config: &Config, path: &Path) -> Result<()> { let json = serde_json::to_string(config)?; // No I/O std::fs::write(path, json)?; // FileWrite detected Ok(()) } }
I/O metadata:
{
"function": "save_config",
"io_operations": ["FileWrite"],
"is_blocking": true,
"affects_purity": true,
"async_safe": false
}
Purity Analysis Integration
DataFlowGraph
integrates with purity detection to provide comprehensive side effect analysis:
Side effect tracking:
- I/O operations (file, network, console)
- Global state mutations
- Random number generation
- System time access
- Non-deterministic behavior
Purity confidence factors:
- 1.0: Pure mathematical function, no side effects
- 0.8: Pure with deterministic data transformations
- 0.5: Mixed - some suspicious patterns
- 0.2: Likely impure - I/O detected
- 0.0: Definitely impure - multiple side effects
Example analysis:
{
"function": "calculate_discount",
"is_pure": true,
"purity_confidence": 0.95,
"side_effects": [],
"deterministic": true,
"safe_to_parallelize": true,
"safe_to_cache": true
}
Modification Impact Analysis
DataFlowGraph
calculates the impact of modifying a function:
#![allow(unused)] fn main() { pub struct ModificationImpact { pub function_name: String, pub affected_functions: Vec<String>, // Upstream callers pub dependency_count: usize, // Downstream callees pub has_side_effects: bool, pub risk_level: RiskLevel, } }
Risk level calculation:
- Critical: Many upstream callers + side effects + low test coverage
- High: Many callers OR side effects with moderate coverage
- Medium: Few callers with side effects OR many callers with good coverage
- Low: Few callers, no side effects, or well-tested
Example impact analysis:
{
"function": "validate_payment_method",
"modification_impact": {
"affected_functions": [
"process_payment",
"refund_payment",
"update_payment_method",
"validate_subscription"
],
"affected_count": 4,
"dependency_count": 8,
"has_side_effects": true,
"io_operations": ["DatabaseRead", "NetworkCall"],
"risk_level": "High",
"recommendation": "Comprehensive testing required - 4 functions depend on this, performs I/O"
}
}
Using modification impact:
# Analyze impact before refactoring
debtmap analyze . --format json | jq '.functions[] | select(.name == "validate_payment_method") | .modification_impact'
Impact analysis uses:
- Refactoring planning: Understand blast radius before changes
- Test prioritization: Focus tests on high-impact functions
- Code review: Flag high-risk changes for extra scrutiny
- Dependency management: Identify tightly coupled components
DataFlowGraph Methods
Key methods for data flow analysis:
#![allow(unused)] fn main() { // Add function with its dependencies pub fn add_function(&mut self, function_id: String, callees: Vec<String>) // Track variable dependencies pub fn add_variable_dependency(&mut self, function_id: String, var_name: String) // Record I/O operations pub fn add_io_operation(&mut self, function_id: String, io_type: IoType) // Calculate modification impact pub fn calculate_modification_impact(&self, function_id: &str) -> ModificationImpact // Get all functions affected by a change pub fn get_affected_functions(&self, function_id: &str) -> Vec<String> // Find functions with side effects pub fn find_functions_with_side_effects(&self) -> Vec<String> }
Integration in analysis pipeline:
- Parser builds initial call graph
- DataFlowGraph extends with variable/I/O tracking
- Purity analyzer adds side effect information
- Modification impact calculated for each function
- Results used in prioritization and risk scoring
Connection to Unified Scoring:
The dependency analysis from DataFlowGraph directly feeds into the unified scoring system’s dependency factor (20% weight):
- Dependency Factor Calculation: Functions with high upstream caller count or on critical paths from entry points receive higher dependency scores (8-10)
- Isolated Utilities: Functions with few or no callers score lower (1-3) on dependency factor
- Impact Prioritization: This helps prioritize functions where bugs have wider impact across the codebase
- Modification Risk: The modification impact analysis uses dependency data to calculate blast radius when changes are made
Example:
Function: validate_payment_method
Upstream callers: 4 (high impact)
→ Dependency Factor: 8.0
Function: format_currency_string
Upstream callers: 0 (utility)
→ Dependency Factor: 1.5
Both have same complexity, but validate_payment_method gets higher unified score
due to its critical role in the call graph.
This integration ensures that the unified scoring system considers not just internal function complexity and test coverage, but also the function’s importance in the broader codebase architecture.
Entropy-Based Complexity
Advanced pattern detection to reduce false positives.
Token Classification:
#![allow(unused)] fn main() { enum TokenType { Variable, // Weight: 1.0 Method, // Weight: 1.5 (more important) Literal, // Weight: 0.5 (less important) Keyword, // Weight: 0.8 Operator, // Weight: 0.6 } }
Shannon Entropy Calculation:
H(X) = -Σ p(x) × log₂(p(x))
where p(x) is the probability of each token type.
Dampening Decision:
#![allow(unused)] fn main() { if entropy_score.token_entropy < 0.4 && entropy_score.pattern_repetition > 0.6 && entropy_score.branch_similarity > 0.7 { // Apply dampening effective_complexity = base_complexity × (1 - dampening_factor); } }
Output explanation:
Function: validate_input
Cyclomatic: 15 → Effective: 5
Reasoning:
- High pattern repetition detected (85%)
- Low token entropy indicates simple patterns (0.32)
- Similar branch structures found (92% similarity)
- Complexity reduced by 67% due to pattern-based code
Entropy Analysis Caching
EntropyAnalyzer
includes an LRU-style cache for performance optimization when analyzing large codebases or performing repeated analysis.
Cache Structure
#![allow(unused)] fn main() { struct CacheEntry { score: EntropyScore, timestamp: Instant, hit_count: usize, } }
Cache configuration:
- Default size: 1000 entries
- Eviction policy: LRU (Least Recently Used)
- Memory per entry: ~128 bytes
- Total memory overhead: ~128 KB for default size
Cache Statistics
The analyzer tracks cache performance:
#![allow(unused)] fn main() { pub struct CacheStats { pub hits: usize, pub misses: usize, pub evictions: usize, pub hit_rate: f64, pub memory_bytes: usize, } }
Example stats output:
{
"entropy_cache_stats": {
"hits": 3427,
"misses": 1573,
"evictions": 573,
"hit_rate": 0.685,
"memory_bytes": 128000
}
}
Hit rate interpretation:
- > 0.7: Excellent - many repeated analyses, cache is effective
- 0.4-0.7: Good - moderate reuse, typical for incremental analysis
- < 0.4: Low - mostly unique functions, cache less helpful
Performance Benefits
Typical performance gains:
- Cold analysis: 100ms baseline (no cache benefit)
- Incremental analysis: 30-40ms (~60-70% faster) for unchanged functions
- Re-analysis: 15-20ms (~80-85% faster) for recently analyzed functions
Best for:
- Watch mode: Analyzing on file save (repeated analysis of same files)
- CI/CD: Comparing feature branch to main (overlap in functions)
- Large codebases: Many similar functions benefit from pattern caching
Memory estimation:
Total cache memory = entry_count × 128 bytes
Examples:
- 1,000 entries: ~128 KB (default)
- 5,000 entries: ~640 KB (large projects)
- 10,000 entries: ~1.25 MB (very large)
Cache Management
Automatic eviction:
- When cache reaches size limit, oldest entries evicted
- Hit count influences retention (frequently accessed stay longer)
- Timestamp used for LRU ordering
Cache invalidation:
- Function source changes invalidate entry
- Cache cleared between major analysis runs
- No manual invalidation needed
Configuration (if exposed in future):
[entropy.cache]
enabled = true
size = 1000 # Number of entries
ttl_seconds = 3600 # Optional: expire after 1 hour
Context-Aware Analysis
Debtmap adjusts analysis based on code context:
Pattern Recognition:
- Validation patterns (repetitive checks)
- Dispatcher patterns (routing logic)
- Builder patterns (fluent APIs)
- Configuration parsers (key-value processing)
Adjustment Strategies:
- Reduce false positives for recognized patterns
- Apply appropriate thresholds by pattern type
- Consider pattern confidence in scoring
Example:
#![allow(unused)] fn main() { // Recognized as "validation_pattern" // Complexity dampening applied fn validate_user_input(input: &UserInput) -> Result<()> { if input.name.is_empty() { return Err(Error::EmptyName); } if input.email.is_empty() { return Err(Error::EmptyEmail); } if input.age < 13 { return Err(Error::TooYoung); } // ... more similar validations Ok(()) } }
Coverage Integration
Debtmap parses LCOV coverage data for risk analysis:
LCOV Support:
- Standard format from most coverage tools
- Line-level coverage tracking
- Function-level aggregation
Coverage Index:
- O(1) exact name lookups (~0.5μs)
- O(log n) line-based fallback (~5-8μs)
- ~200 bytes per function
- Thread-safe (Arc
)
Performance Characteristics
Index Build Performance:
- Index construction: O(n), approximately 20-30ms for 5,000 functions
- Memory usage: ~200 bytes per record (~2MB for 5,000 functions)
- Scales linearly with function count
Lookup Performance:
- Exact match (function name): O(1) average, ~0.5μs per lookup
- Line-based fallback: O(log n), ~5-8μs per lookup
- Cache-friendly data structure for hot paths
Analysis Overhead:
- Coverage integration overhead: ~2.5x baseline analysis time
- Target overhead: ≤3x (maintained through optimizations)
- Example timing: 53ms baseline → 130ms with coverage (2.45x overhead)
- Overhead includes index build + lookups + coverage propagation
Thread Safety:
- Coverage index wrapped in
Arc<CoverageIndex>
for lock-free parallel access - Multiple analyzer threads can query coverage simultaneously
- No contention on reads, suitable for parallel analysis pipelines
Memory Footprint:
Total memory = (function_count × 200 bytes) + index overhead
Examples:
- 1,000 functions: ~200 KB
- 5,000 functions: ~2 MB
- 10,000 functions: ~4 MB
Scalability:
- Tested with codebases up to 10,000 functions
- Performance remains predictable and acceptable
- Memory usage stays bounded and reasonable
Generating coverage:
# Rust
cargo tarpaulin --out lcov --output-dir target/coverage
# Python
pytest --cov --cov-report=lcov
# JavaScript/TypeScript
jest --coverage --coverageReporters=lcov
# Go
go test -coverprofile=coverage.out
gocover-cobertura < coverage.out > coverage.lcov
Using with Debtmap:
debtmap analyze . --lcov target/coverage/lcov.info
Coverage dampening: When coverage data is provided, debt scores are dampened for well-tested code:
final_score = base_score × (1 - coverage_percentage)
This ensures well-tested complex code gets lower priority than untested simple code.
Example Outputs
High Complexity Function (Needs Refactoring)
Terminal Output:
#1 SCORE: 9.2 [CRITICAL]
├─ COMPLEXITY: ./src/payments/processor.rs:145 process_transaction()
├─ ACTION: Refactor into 4 smaller functions
├─ IMPACT: Reduce complexity from 25 to 8, improve testability
├─ COMPLEXITY: cyclomatic=25, branches=25, cognitive=38, nesting=5, lines=120
├─ DEPENDENCIES: 3 upstream, 8 downstream
└─ WHY: Exceeds all complexity thresholds, difficult to test and maintain
JSON Output:
{
"id": "complexity_src_payments_processor_rs_145",
"debt_type": "Complexity",
"priority": "Critical",
"file": "src/payments/processor.rs",
"line": 145,
"message": "Function exceeds complexity threshold",
"context": "Cyclomatic: 25, Cognitive: 38, Nesting: 5",
"function_metrics": {
"name": "process_transaction",
"cyclomatic": 25,
"cognitive": 38,
"nesting": 5,
"length": 120,
"is_pure": false,
"purity_confidence": 0.15,
"upstream_callers": ["handle_payment", "handle_subscription", "handle_refund"],
"downstream_callees": ["validate", "calculate_fees", "record_transaction", "send_receipt", "update_balance", "log_transaction", "check_fraud", "notify_user"]
}
}
Well-Tested Complex Function (Good Example)
Terminal Output:
Function: calculate_tax (WELL TESTED - Good Example!)
File: src/tax/calculator.rs:78
Complexity: Cyclomatic=18, Cognitive=22
Coverage: 98%
Risk: LOW
Why this is good:
- High complexity is necessary (tax rules are complex)
- Thoroughly tested with 45 test cases
- Clear documentation of edge cases
- Good example to follow for other complex logic
Test Gap (Needs Testing)
Terminal Output:
#2 SCORE: 8.9 [CRITICAL]
├─ TEST GAP: ./src/analyzers/rust_call_graph.rs:38 add_function_to_graph()
├─ ACTION: Add 6 unit tests for full coverage
├─ IMPACT: Full test coverage, -3.7 risk reduction
├─ COMPLEXITY: cyclomatic=6, branches=6, cognitive=8, nesting=2, lines=32
├─ DEPENDENCIES: 0 upstream, 11 downstream
├─ TEST EFFORT: Simple (2-3 hours)
└─ WHY: Business logic with 0% coverage, manageable complexity (cyclo=6, cog=8)
High impact - 11 functions depend on this
JSON Output:
{
"function": "add_function_to_graph",
"file": "src/analyzers/rust_call_graph.rs",
"line": 38,
"current_risk": 8.9,
"potential_risk_reduction": 3.7,
"recommendation": {
"action": "Add unit tests",
"details": "Add 6 unit tests for full coverage",
"effort_estimate": "2-3 hours"
},
"test_effort": {
"estimated_difficulty": "Simple",
"cognitive_load": 8,
"branch_count": 6,
"recommended_test_cases": 6
},
"complexity": {
"cyclomatic": 6,
"cognitive": 8,
"nesting": 2,
"length": 32
},
"dependencies": {
"upstream_callers": [],
"downstream_callees": [
"get_function_name", "extract_parameters", "parse_return_type",
"add_to_registry", "update_call_sites", "resolve_types",
"track_visibility", "record_location", "increment_counter",
"validate_signature", "log_registration"
]
},
"roi": 4.5
}
Entropy-Dampened Validation Function
Terminal Output:
Function: validate_config
File: src/config/validator.rs:23
Cyclomatic: 20 → Effective: 7 (65% dampened)
Risk: LOW
Entropy Analysis:
├─ Token Entropy: 0.28 (low variety - repetitive patterns)
├─ Pattern Repetition: 0.88 (high similarity between checks)
├─ Branch Similarity: 0.91 (consistent validation structure)
└─ Reasoning: Complexity reduced by 65% due to pattern-based code
This appears complex but is actually a repetitive validation pattern.
Lower priority for refactoring.
Before/After Refactoring Comparison
Before:
Function: process_order
Cyclomatic: 22
Cognitive: 35
Coverage: 15%
Risk Score: 52.3 (CRITICAL)
Debt Score: 50 (Critical Complexity)
After:
Function: process_order (refactored)
Cyclomatic: 5
Cognitive: 6
Coverage: 92%
Risk Score: 2.1 (LOW)
Debt Score: 0 (no debt)
Extracted functions:
- validate_order (Cyclomatic: 4, Coverage: 100%)
- calculate_totals (Cyclomatic: 3, Coverage: 95%)
- apply_discounts (Cyclomatic: 6, Coverage: 88%)
- finalize_order (Cyclomatic: 4, Coverage: 90%)
Impact:
✓ Complexity reduced by 77%
✓ Coverage improved by 513%
✓ Risk reduced by 96%
✓ Created 4 focused, testable functions
Next Steps
- Output Formats - Detailed JSON schema and integration patterns
- Configuration - Customize thresholds and analysis behavior
For questions or issues, visit GitHub Issues.
Configuration
Debtmap is highly configurable through a .debtmap.toml
file. This chapter explains how to customize Debtmap’s behavior for your project’s specific needs.
Config Files
Creating a Configuration File
Debtmap looks for a .debtmap.toml
file in the current directory and up to 10 parent directories. To create an initial configuration:
debtmap init
This command creates a .debtmap.toml
file with sensible defaults.
Configuration File Discovery
When you run debtmap
, it searches for .debtmap.toml
starting in your current directory and traversing up to 10 parent directories. The first configuration file found is used.
If no configuration file is found, Debtmap uses built-in defaults that work well for most projects.
Basic Example
Here’s a minimal .debtmap.toml
configuration:
[scoring]
coverage = 0.50 # 50% weight for test coverage gaps
complexity = 0.35 # 35% weight for code complexity
dependency = 0.15 # 15% weight for dependency criticality
[thresholds]
complexity = 10
max_file_length = 500
max_function_length = 50
[languages]
enabled = ["rust", "python", "javascript", "typescript"]
Scoring Configuration
Scoring Weights
The [scoring]
section controls how different factors contribute to the overall debt score. Debtmap uses a weighted sum model where weights must sum to 1.0.
[scoring]
coverage = 0.50 # Weight for test coverage gaps (default: 0.50)
complexity = 0.35 # Weight for code complexity (default: 0.35)
dependency = 0.15 # Weight for dependency criticality (default: 0.15)
Active weights (used in scoring):
coverage
- Prioritizes untested code (default: 0.50)complexity
- Identifies complex areas (default: 0.35)dependency
- Considers impact radius (default: 0.15)
Unused weights (reserved for future features):
semantic
- Not currently used (default: 0.00)security
- Not currently used (default: 0.00)organization
- Not currently used (default: 0.00)
Validation rules:
- All weights must be between 0.0 and 1.0
- Active weights (coverage + complexity + dependency) must sum to 1.0 (±0.001 tolerance)
- If weights don’t sum to 1.0, they will be automatically normalized
Example - Prioritize complexity over coverage:
[scoring]
coverage = 0.30
complexity = 0.55
dependency = 0.15
Role Multipliers
Role multipliers adjust complexity scores based on a function’s semantic role:
[role_multipliers]
pure_logic = 1.2 # Prioritize pure computation (default: 1.2)
orchestrator = 0.8 # Reduce for delegation functions (default: 0.8)
io_wrapper = 0.7 # Reduce for I/O wrappers (default: 0.7)
entry_point = 0.9 # Slight reduction for main/CLI (default: 0.9)
pattern_match = 0.6 # Reduce for pattern matching (default: 0.6)
unknown = 1.0 # No adjustment (default: 1.0)
These multipliers help reduce false positives by recognizing that different function types have naturally different complexity levels.
Role Coverage Weights
Adjust how coverage gaps are weighted based on function role:
[role_coverage_weights]
entry_point = 0.6 # Reduce coverage penalty (often integration tested)
orchestrator = 0.8 # Reduce coverage penalty (tested via higher-level tests)
pure_logic = 1.0 # Full penalty (should have unit tests)
io_wrapper = 1.0 # Full penalty (should have unit tests)
pattern_match = 1.0 # Full penalty (should have unit tests)
unknown = 1.0 # Full penalty (default behavior)
Entry points and orchestrators get reduced coverage penalties since they’re often tested through integration tests rather than unit tests.
Thresholds Configuration
Basic Thresholds
Control when code is flagged as technical debt:
[thresholds]
complexity = 10 # Cyclomatic complexity threshold
duplication = 50 # Duplication threshold
max_file_length = 500 # Maximum lines per file
max_function_length = 50 # Maximum lines per function
Minimum Thresholds
Filter out trivial functions that aren’t really technical debt:
[thresholds]
minimum_debt_score = 2.0 # Only show items with debt score ≥ 2.0
minimum_cyclomatic_complexity = 3 # Ignore functions with cyclomatic < 3
minimum_cognitive_complexity = 5 # Ignore functions with cognitive < 5
minimum_risk_score = 2.0 # Only show Risk items with score ≥ 2.0
These minimum thresholds help focus on significant issues by filtering out simple functions with minor complexity.
Validation Thresholds
The [thresholds.validation]
subsection configures limits for the debtmap validate
command:
[thresholds.validation]
max_average_complexity = 10.0 # Maximum allowed average complexity (default: 10.0)
max_high_complexity_count = 100 # Maximum high complexity functions (default: 100)
max_debt_items = 2000 # Maximum technical debt items (default: 2000)
max_total_debt_score = 1000 # Maximum total debt score (default: 1000)
max_codebase_risk_score = 7.0 # Maximum codebase risk score (default: 7.0)
max_high_risk_functions = 50 # Maximum high-risk functions (default: 50)
min_coverage_percentage = 0.0 # Minimum required coverage % (default: 0.0)
max_debt_density = 50.0 # Maximum debt per 1000 LOC (default: 50.0)
Use debtmap validate
in CI to enforce code quality standards:
# Fail build if validation thresholds are exceeded
debtmap validate
Language Configuration
Enabling Languages
Specify which languages to analyze:
[languages]
enabled = ["rust", "python", "javascript", "typescript"]
Language-Specific Features
Configure features for individual languages:
[languages.rust]
detect_dead_code = false # Rust: disabled by default (compiler handles it)
detect_complexity = true
detect_duplication = true
[languages.python]
detect_dead_code = true
detect_complexity = true
detect_duplication = true
[languages.javascript]
detect_dead_code = true
detect_complexity = true
detect_duplication = true
[languages.typescript]
detect_dead_code = true
detect_complexity = true
detect_duplication = true
Note: Rust’s dead code detection is disabled by default since the Rust compiler already provides excellent unused code warnings.
Exclusion Patterns
File and Directory Exclusion
Use glob patterns to exclude files and directories from analysis:
[ignore]
patterns = [
"target/**", # Rust build output
"venv/**", # Python virtual environment
"node_modules/**", # JavaScript dependencies
"*.min.js", # Minified files
"benches/**", # Benchmark code
"tests/**/*", # Test files
"**/test_*.rs", # Test files (prefix)
"**/*_test.rs", # Test files (suffix)
"**/fixtures/**", # Test fixtures
"**/mocks/**", # Mock implementations
"**/stubs/**", # Stub implementations
"**/examples/**", # Example code
"**/demo/**", # Demo code
]
Glob pattern syntax:
*
- Matches any characters except/
**
- Matches any characters including/
(recursive)?
- Matches a single character[abc]
- Matches any character in the set
Note: Function-level filtering (e.g., ignoring specific function name patterns) is handled by role detection and context-aware analysis rather than explicit ignore patterns. See the Context-Aware Detection section for function-level filtering options.
Display Configuration
Control how results are displayed:
[display]
tiered = true # Use tiered priority display (default: true)
items_per_tier = 5 # Show 5 items per tier (default: 5)
When tiered = true
, Debtmap groups results into priority tiers (Critical, High, Medium, Low) and shows the top items from each tier.
Output Configuration
Set the default output format:
[output]
default_format = "terminal" # Options: "terminal", "json", "markdown"
Supported formats:
"terminal"
- Human-readable colored output for the terminal (default)"json"
- Machine-readable JSON for integration with other tools"markdown"
- Markdown format for documentation and reports
This can be overridden with the --format
CLI flag:
debtmap analyze --format json # JSON output
debtmap analyze --format markdown # Markdown output
Normalization Configuration
Control how raw scores are normalized to a 0-10 scale:
[normalization]
linear_threshold = 10.0 # Use linear scaling below this value
logarithmic_threshold = 100.0 # Use logarithmic scaling above this value
sqrt_multiplier = 3.33 # Multiplier for square root scaling
log_multiplier = 10.0 # Multiplier for logarithmic scaling
show_raw_scores = true # Show both raw and normalized scores
Normalization ensures scores are comparable across different codebases and prevents extreme outliers from dominating the results.
Advanced Configuration
Entropy-Based Complexity Scoring
Entropy analysis helps identify repetitive code patterns (like large match statements) that inflate complexity metrics:
[entropy]
enabled = true # Enable entropy analysis (default: true)
weight = 1.0 # Weight in complexity adjustment (default: 1.0)
min_tokens = 20 # Minimum tokens for analysis (default: 20)
pattern_threshold = 0.7 # Pattern similarity threshold (default: 0.7)
entropy_threshold = 0.4 # Low entropy threshold (default: 0.4)
branch_threshold = 0.8 # Branch similarity threshold (default: 0.8)
use_classification = false # Use smarter token classification (default: false)
# Maximum reductions to prevent over-correction
max_repetition_reduction = 0.20 # Max 20% reduction for repetition (default: 0.20)
max_entropy_reduction = 0.15 # Max 15% reduction for low entropy (default: 0.15)
max_branch_reduction = 0.25 # Max 25% reduction for similar branches (default: 0.25)
max_combined_reduction = 0.30 # Max 30% total reduction (default: 0.30)
Entropy scoring reduces false positives from functions like parsers and state machines that have high cyclomatic complexity but are actually simple and maintainable.
God Object Detection
Configure detection of classes/structs with too many responsibilities:
[god_object_detection]
enabled = true
# Rust-specific thresholds
[god_object_detection.rust]
max_methods = 20 # Maximum methods before flagging (default: 20)
max_fields = 15 # Maximum fields before flagging (default: 15)
max_traits = 5 # Maximum implemented traits
max_lines = 1000 # Maximum lines of code
max_complexity = 200 # Maximum total complexity
# Python-specific thresholds
[god_object_detection.python]
max_methods = 15
max_fields = 10
max_traits = 3
max_lines = 500
max_complexity = 150
# JavaScript-specific thresholds
[god_object_detection.javascript]
max_methods = 15
max_fields = 20 # JavaScript classes often have more properties
max_traits = 3
max_lines = 500
max_complexity = 150
Note: Different languages have different defaults. Rust allows more methods since trait implementations add methods, while JavaScript classes should be smaller.
Context-Aware Detection
Enable context-aware pattern detection to reduce false positives:
[context]
enabled = false # Opt-in (default: false)
# Custom context rules
[[context.rules]]
name = "allow_blocking_in_main"
pattern = "blocking_io"
action = "allow"
priority = 100
reason = "Main function can use blocking I/O"
[context.rules.context]
role = "main"
# Function pattern configuration
[context.function_patterns]
test_patterns = ["test_*", "bench_*"]
config_patterns = ["load_*_config", "parse_*_config"]
handler_patterns = ["handle_*", "*_handler"]
init_patterns = ["initialize_*", "setup_*"]
Context-aware detection adjusts severity based on where code appears (main functions, test code, configuration loaders, etc.).
Error Handling Detection
Configure detection of error handling anti-patterns:
[error_handling]
detect_async_errors = true # Detect async error issues (default: true)
detect_context_loss = true # Detect error context loss (default: true)
detect_propagation = true # Analyze error propagation (default: true)
detect_panic_patterns = true # Detect panic/unwrap usage (default: true)
detect_swallowing = true # Detect swallowed errors (default: true)
# Custom error patterns
[[error_handling.custom_patterns]]
name = "custom_panic"
pattern = "my_panic_macro"
pattern_type = "macro_name"
severity = "high"
description = "Custom panic macro usage"
remediation = "Replace with Result-based error handling"
# Severity overrides
[[error_handling.severity_overrides]]
pattern = "unwrap"
context = "test"
severity = "low" # Unwrap is acceptable in test code
External API Configuration
Mark functions as public API for enhanced testing recommendations:
[external_api]
detect_external_api = false # Auto-detect public APIs (default: false)
api_functions = [] # Explicitly mark API functions
api_files = [] # Explicitly mark API files
When enabled, public API functions receive higher priority for test coverage.
Additional Advanced Options
Debtmap supports additional advanced configuration options:
-
[loc]
- Lines of code counting configuration. Controls whether to include tests (include_tests
), generated files (include_generated
), comments (count_comments
), and blank lines (count_blank_lines
) in LOC counts. All default to false. -
[tiers]
- Tier threshold configuration for prioritization. Allows customization of complexity and dependency thresholds for different priority tiers (T2, T3, T4). Used internally for tiered reporting. -
[complexity_thresholds]
- Enhanced complexity detection thresholds. Configures minimum total, cyclomatic, and cognitive complexity thresholds for flagging functions. Supplements the basic[thresholds]
section with more granular control.
These options are advanced features with sensible defaults. Most users won’t need to configure them explicitly.
CLI Integration
CLI flags can override configuration file settings:
# Override complexity threshold
debtmap analyze --threshold-complexity 15
# Provide coverage file
debtmap analyze --coverage-file coverage.json
# Enable context-aware detection
debtmap analyze --context
# Override output format
debtmap analyze --format json
CLI flags take precedence over .debtmap.toml
settings, allowing per-run customization.
Configuration Validation
Automatic Validation
Debtmap automatically validates your configuration when loading:
- Scoring weights must sum to 1.0 (±0.001 tolerance)
- Individual weights must be between 0.0 and 1.0
- Invalid configurations fall back to defaults with a warning
Normalization
If scoring weights don’t sum exactly to 1.0, Debtmap automatically normalizes them:
# Input (sums to 0.80)
[scoring]
coverage = 0.40
complexity = 0.30
dependency = 0.10
# Automatically normalized to:
# coverage = 0.50
# complexity = 0.375
# dependency = 0.125
Debug Validation
To verify which configuration file is being loaded, check debug logs:
RUST_LOG=debug debtmap analyze
Look for log messages like:
DEBUG debtmap::config: Loaded config from /path/to/.debtmap.toml
Complete Configuration Example
Here’s a comprehensive configuration showing all major sections:
# Scoring configuration
[scoring]
coverage = 0.50
complexity = 0.35
dependency = 0.15
# Basic thresholds
[thresholds]
complexity = 10
duplication = 50
max_file_length = 500
max_function_length = 50
minimum_debt_score = 2.0
minimum_cyclomatic_complexity = 3
minimum_cognitive_complexity = 5
minimum_risk_score = 2.0
# Validation thresholds for CI
[thresholds.validation]
max_average_complexity = 10.0
max_high_complexity_count = 100
max_debt_items = 2000
max_total_debt_score = 1000
max_codebase_risk_score = 7.0
max_high_risk_functions = 50
min_coverage_percentage = 0.0
max_debt_density = 50.0
# Language configuration
[languages]
enabled = ["rust", "python", "javascript", "typescript"]
[languages.rust]
detect_dead_code = false
detect_complexity = true
detect_duplication = true
# Exclusion patterns
[ignore]
patterns = [
"target/**",
"node_modules/**",
"tests/**/*",
"**/*_test.rs",
]
# Display configuration
[display]
tiered = true
items_per_tier = 5
# Output configuration
[output]
default_format = "terminal"
# Entropy configuration
[entropy]
enabled = true
weight = 1.0
min_tokens = 20
# God object detection
[god_object_detection]
enabled = true
[god_object_detection.rust]
max_methods = 20
max_fields = 15
Configuration Best Practices
For Strict Quality Standards
[scoring]
coverage = 0.60 # Emphasize test coverage
complexity = 0.30
dependency = 0.10
[thresholds]
minimum_debt_score = 3.0 # Higher bar for flagging issues
max_function_length = 30 # Enforce smaller functions
[thresholds.validation]
max_average_complexity = 8.0 # Stricter complexity limits
max_debt_items = 500 # Stricter debt limits
min_coverage_percentage = 80.0 # Require 80% coverage
For Legacy Codebases
[scoring]
coverage = 0.30 # Reduce coverage weight (legacy code often lacks tests)
complexity = 0.50 # Focus on complexity
dependency = 0.20
[thresholds]
minimum_debt_score = 5.0 # Only show highest priority items
minimum_cyclomatic_complexity = 10 # Filter out moderate complexity
[thresholds.validation]
max_debt_items = 10000 # Accommodate large debt
max_total_debt_score = 5000 # Higher limits for legacy code
For Open Source Libraries
[scoring]
coverage = 0.55 # Prioritize test coverage (public API)
complexity = 0.30
dependency = 0.15
[external_api]
detect_external_api = true # Flag untested public APIs
[thresholds.validation]
min_coverage_percentage = 90.0 # High coverage for public API
max_high_complexity_count = 20 # Keep complexity low
Troubleshooting
Configuration Not Loading
Check file location:
# Ensure file is named .debtmap.toml (note the dot prefix)
ls -la .debtmap.toml
# Debtmap searches current directory + 10 parent directories
pwd
Check file syntax:
# Verify TOML syntax is valid
debtmap analyze 2>&1 | grep -i "failed to parse"
Weights Don’t Sum to 1.0
Error message:
Warning: Invalid scoring weights: Active scoring weights must sum to 1.0, but sum to 0.800. Using defaults.
Fix: Ensure coverage + complexity + dependency = 1.0
[scoring]
coverage = 0.50
complexity = 0.35
dependency = 0.15 # Sum = 1.0 ✓
No Results Shown
Possible causes:
- Minimum thresholds too high
- All code excluded by ignore patterns
- No supported languages in project
Solutions:
# Lower minimum thresholds
[thresholds]
minimum_debt_score = 1.0
minimum_cyclomatic_complexity = 1
# Check language configuration
[languages]
enabled = ["rust", "python", "javascript", "typescript"]
# Review ignore patterns
[ignore]
patterns = [
# Make sure you're not excluding too much
]
Related Chapters
- Getting Started - Initial setup and basic usage
- Analysis Guide - Understanding scoring and prioritization
- Output Formats - Formatting and exporting results
Output Formats
Debtmap provides multiple output formats to suit different workflows, from interactive terminal reports to machine-readable JSON for CI/CD integration. This chapter covers all available formats and how to use them effectively.
Format Selection
Select the output format using the -f
or --format
flag:
# Terminal output (default) - human-readable with colors
debtmap analyze .
# JSON output - machine-readable for tooling
debtmap analyze . --format json
# Markdown output - documentation and reports
debtmap analyze . --format markdown
Available formats:
- terminal (default): Interactive output with colors, emoji, and formatting
- json: Structured data for programmatic processing
- markdown: Reports suitable for documentation and PR comments
Writing to Files
By default, output goes to stdout. Use -o
or --output
to write to a file:
# Write JSON to file
debtmap analyze . --format json -o report.json
# Write markdown report
debtmap analyze . --format markdown -o DEBT_REPORT.md
# Terminal output to file (preserves colors)
debtmap analyze . -o analysis.txt
Terminal Output
The terminal format provides an interactive, color-coded report designed for developer workflows. It’s the default format and optimized for readability.
Output Structure
Terminal output is organized into five main sections:
- Header - Analysis report title
- Codebase Summary - High-level metrics and debt score
- Complexity Hotspots - Top 5 most complex functions with refactoring guidance
- Technical Debt - High-priority debt items requiring attention
- Pass/Fail Status - Overall quality assessment
Example Terminal Output
═══════════════════════════════════════════
DEBTMAP ANALYSIS REPORT
═══════════════════════════════════════════
📊 CODEBASE Summary
───────────────────────────────────────────
Files analyzed: 42
Total functions: 287
Average complexity: 6.3
Debt items: 15
Total debt score: 156 (threshold: 100)
⚠️ COMPLEXITY HOTSPOTS (Top 5)
───────────────────────────────────────────
1. src/analyzers/rust.rs:245 parse_function() - Cyclomatic: 18, Cognitive: 24
ACTION: Extract 3-5 pure functions using decompose-then-transform strategy
PATTERNS: Decompose into logical units, then apply functional patterns
BENEFIT: Pure functions are easily testable and composable
2. src/debt/smells.rs:196 detect_data_clumps() - Cyclomatic: 15, Cognitive: 20
↓ Entropy: 0.32, Repetition: 85%, Effective: 0.6x
High pattern repetition detected (85%)
🔧 TECHNICAL DEBT (15 items)
───────────────────────────────────────────
High Priority (5):
- src/risk/scoring.rs:142 - TODO: Implement caching for score calculations
- src/core/metrics.rs:89 - High complexity: cyclomatic=16
- src/debt/patterns.rs:201 - Code duplication: 65 lines duplicated
✓ Pass/Fail: PASS
Color Coding and Symbols
The terminal output uses colors and symbols for quick visual scanning:
Status Indicators:
- ✓ Green: Passing, good, well-tested
- ⚠️ Yellow: Warning, moderate complexity
- ✗ Red: Failing, critical, high complexity
- 📊 Blue: Information, metrics
- 🔧 Orange: Technical debt items
- 🎯 Cyan: Recommendations
Complexity Classification:
- LOW (0-5): Green - Simple, easy to maintain
- MODERATE (6-10): Yellow - Consider refactoring
- HIGH (11-15): Orange - Should refactor
- SEVERE (>15): Red - Urgent refactoring needed
Note: These levels match the
ComplexityLevel
enum in the implementation.
Debt Score Thresholds:
The default debt threshold is 100. Scores are colored based on this threshold:
- Green (≤50): Healthy - Below half threshold (score ≤ threshold/2)
- Yellow (51-100): Attention needed - Between half and full threshold (threshold/2 < score ≤ threshold)
- Red (>100): Action required - Exceeds threshold (score > threshold)
Note: Boundary values use strict inequalities: 50 is Green, 100 is Yellow (not Red), 101+ is Red.
Refactoring Guidance
For complex functions (cyclomatic complexity > 5), the terminal output provides actionable refactoring recommendations:
ACTION: Extract 3-5 pure functions using decompose-then-transform strategy
PATTERNS: Decompose into logical units, then apply functional patterns
BENEFIT: Pure functions are easily testable and composable
Guidance levels:
- Moderate (6-10): Extract 2-3 pure functions using direct functional transformation
- High (11-15): Extract 3-5 pure functions using decompose-then-transform strategy
- Severe (>15): Extract 5+ pure functions into modules with functional core/imperative shell
See the Analysis Guide for metric explanations.
Plain Terminal Mode
For environments without color support or when piping to tools, use --plain
:
# ASCII-only output, no colors, no emoji
debtmap analyze . --plain
Plain mode:
- Removes ANSI color codes
- Replaces emoji with text labels
- Uses ASCII box-drawing characters
- Machine-parseable structure
Note: Terminal output formatting (colors, symbols, etc.) can be customized internally via
FormattingConfig
. These customization options are currently not exposed through the CLI interface.
Verbosity Levels
Control detail level with -v
flags (can be repeated):
# Standard output
debtmap analyze .
# Level 1: Show main score factors
debtmap analyze . -v
# Level 2: Show detailed calculations
debtmap analyze . -vv
# Level 3: Show all debug information
debtmap analyze . -vvv
Verbosity features:
-v
: Show main score factors (complexity, coverage, dependency breakdown)-vv
: Show detailed calculations with formulas and intermediate values-vvv
: Show all debug information including entropy metrics, role detection, and cache hits
Note: Verbosity flags affect terminal output only. JSON and markdown formats include all data regardless of verbosity level.
Each level includes all information from the previous levels, progressively adding more detail to help understand how scores are calculated.
Example Output Differences:
Standard output shows basic metrics:
Total debt score: 156 (threshold: 100)
Level 1 (-v
) adds score breakdowns:
Total debt score: 156 (threshold: 100)
Complexity contribution: 85 (54%)
Coverage gaps: 45 (29%)
Dependency issues: 26 (17%)
Level 2 (-vv
) adds detailed calculations:
Total debt score: 156 (threshold: 100)
Complexity contribution: 85 (54%)
Formula: sum(cyclomatic_weight * severity_multiplier)
High complexity functions: 5 × 12 = 60
Medium complexity: 8 × 3 = 24
Base penalty: 1
Coverage gaps: 45 (29%)
Uncovered complex functions: 3 × 15 = 45
Level 3 (-vvv
) adds all internal details:
Total debt score: 156 (threshold: 100)
... (all level 2 output) ...
Debug info:
Entropy metrics cached: 42/50 functions
Function role detection: BusinessLogic=12, Utility=8, TestHelper=5
Cache hit rate: 84%
Risk Analysis Output
When coverage data is provided via --lcov
, terminal output includes a dedicated risk analysis section:
═══════════════════════════════════════════
RISK ANALYSIS REPORT
═══════════════════════════════════════════
📈 RISK Summary
───────────────────────────────────────────
Codebase Risk Score: 45.5 (MEDIUM)
Complexity-Coverage Correlation: -0.65
Risk Distribution:
Critical: 2 functions
High: 5 functions
Medium: 10 functions
Low: 15 functions
Well Tested: 20 functions
🎯 CRITICAL RISKS
───────────────────────────────────────────
1. src/core/parser.rs:142 parse_complex_ast()
Risk: 85.0 | Complexity: 15 | Coverage: 0%
Recommendation: Add 5 unit tests (est: 2-3 hours)
Impact: -40 risk reduction
💡 RECOMMENDATIONS (by ROI)
───────────────────────────────────────────
1. test_me() - ROI: 5.0x
Current Risk: 75 | Reduction: 40 | Effort: Moderate
Rationale: High risk function with low coverage
Risk Level Classification:
- LOW (<30): Green - score < 30.0
- MEDIUM (30-59): Yellow - 30.0 ≤ score < 60.0
- HIGH (≥60): Red - score ≥ 60.0
Note: 60 is the start of HIGH risk level.
JSON Output
JSON output provides complete analysis results in a machine-readable format, ideal for CI/CD pipelines, custom tooling, and programmatic analysis.
Basic Usage
# Generate JSON output
debtmap analyze . --format json
# Save to file
debtmap analyze . --format json -o report.json
# Pretty-printed by default for readability
debtmap analyze . --format json | jq .
Note: JSON output is automatically pretty-printed for readability.
JSON Schema Structure
Debtmap outputs a structured JSON document with the following top-level fields:
{
"project_path": "/path/to/project",
"timestamp": "2025-01-09T12:00:00Z",
"complexity": { ... },
"technical_debt": { ... },
"dependencies": { ... },
"duplications": [ ... ]
}
Full Schema Example
Here’s a complete annotated JSON output example:
{
// Project metadata
"project_path": "/Users/dev/myproject",
"timestamp": "2025-01-09T15:30:00Z",
// Complexity analysis results
"complexity": {
"metrics": [
{
"name": "calculate_risk_score",
"file": "src/risk/scoring.rs",
"line": 142,
"cyclomatic": 12,
"cognitive": 18,
"nesting": 4,
"length": 85,
"is_test": false,
"visibility": "pub",
"is_trait_method": false,
"in_test_module": false,
"entropy_score": {
"token_entropy": 0.65,
"pattern_repetition": 0.30,
"branch_similarity": 0.45,
"effective_complexity": 0.85
},
"is_pure": false,
"purity_confidence": 0.75,
"detected_patterns": ["nested_loops", "complex_conditionals"],
"upstream_callers": ["analyze_codebase", "generate_report"],
"downstream_callees": ["get_metrics", "apply_weights"]
}
],
"summary": {
"total_functions": 287,
"average_complexity": 6.3,
"max_complexity": 24,
"high_complexity_count": 12
}
},
// Technical debt items
"technical_debt": {
"items": [
{
"id": "debt_001",
"debt_type": "Complexity",
"priority": "High",
"file": "src/analyzers/rust.rs",
"line": 245,
"column": 5,
"message": "High cyclomatic complexity: 18",
"context": "Function parse_function has excessive branching"
},
{
"id": "debt_002",
"debt_type": "Todo",
"priority": "Medium",
"file": "src/core/cache.rs",
"line": 89,
"column": null,
"message": "TODO: Implement LRU eviction policy",
"context": null
}
],
"by_type": {
"Complexity": [ /* same structure as items */ ],
"Todo": [ /* ... */ ],
"Duplication": [ /* ... */ ]
},
"priorities": ["Low", "Medium", "High", "Critical"]
},
// Dependency analysis
"dependencies": {
"modules": [
{
"module": "risk::scoring",
"dependencies": ["core::metrics", "debt::patterns"],
"dependents": ["commands::analyze", "io::output"]
}
],
"circular": [
{
"cycle": ["module_a", "module_b", "module_c", "module_a"]
}
]
},
// Code duplication blocks
"duplications": [
{
"hash": "abc123def456",
"lines": 15,
"locations": [
{
"file": "src/parser/rust.rs",
"start_line": 42,
"end_line": 57
},
{
"file": "src/parser/python.rs",
"start_line": 89,
"end_line": 104
}
]
}
]
}
Field Descriptions
FunctionMetrics Fields:
-
name
: Function name -
file
: Path to source file -
line
: Line number where function is defined -
cyclomatic
: Cyclomatic complexity score -
cognitive
: Cognitive complexity score -
nesting
: Maximum nesting depth -
length
: Lines of code in function -
is_test
: Whether this is a test function -
visibility
: Rust visibility modifier (pub, pub(crate), or null) -
is_trait_method
: Whether this implements a trait -
in_test_module
: Whether inside #[cfg(test)] -
entropy_score
: Optional entropy analysis with structure:{ "token_entropy": 0.65, // Token distribution entropy (0-1): measures variety of tokens "pattern_repetition": 0.30, // Pattern repetition score (0-1): detects repeated code patterns "branch_similarity": 0.45, // Branch similarity metric (0-1): compares similarity between branches "effective_complexity": 0.85 // Adjusted complexity multiplier: complexity adjusted for entropy }
EntropyScore Fields:
token_entropy
: Measures the variety and distribution of tokens in the function (0-1, higher = more variety)pattern_repetition
: Detects repeated code patterns within the function (0-1, higher = more repetition)branch_similarity
: Measures similarity between different code branches (0-1, higher = more similar)effective_complexity
: The overall complexity multiplier adjusted for entropy effects
-
is_pure
: Whether function is pure (no side effects) -
purity_confidence
: Confidence level (0.0-1.0) -
detected_patterns
: List of detected code patterns -
upstream_callers
: Functions that call this one -
downstream_callees
: Functions this one calls
DebtItem Fields:
id
: Unique identifierdebt_type
: Type of debt (see DebtType enum below)priority
: Priority level (Low, Medium, High, Critical)file
: Path to file containing debtline
: Line numbercolumn
: Optional column numbermessage
: Human-readable descriptioncontext
: Optional additional context
DebtType Enum:
Todo
: TODO markersFixme
: FIXME markersCodeSmell
: Code smell patternsDuplication
: Duplicated codeComplexity
: Excessive complexityDependency
: Dependency issuesErrorSwallowing
: Suppressed errorsResourceManagement
: Resource management issuesCodeOrganization
: Organizational problemsTestComplexity
: Complex test codeTestTodo
: TODOs in testsTestDuplication
: Duplicated test codeTestQuality
: Test quality issues
JSON Format Variants
Debtmap supports two JSON output formats:
# Legacy format (default) - backward compatible
debtmap analyze . --format json --output-format legacy
# Unified format - new consistent structure
debtmap analyze . --format json --output-format unified
Note: The
--output-format
flag only applies when using--format json
. It has no effect with markdown or terminal formats.
Legacy format: Uses {File: {...}}
and {Function: {...}}
wrappers for backward compatibility with existing tooling.
Unified format: Consistent structure with a type
field, making parsing simpler and more predictable. Recommended for new integrations.
Risk Insights JSON
When using --lcov
, debtmap also outputs risk analysis in JSON:
{
"items": [
{
"location": {
"file": "src/risk/scoring.rs",
"function": "calculate_priority",
"line": 66
},
"debt_type": "TestGap",
"unified_score": {
"complexity_factor": 3.2,
"coverage_factor": 10.0,
"dependency_factor": 2.5,
"role_multiplier": 1.2,
"final_score": 9.4
},
"function_role": "BusinessLogic",
"recommendation": {
"action": "Add unit tests",
"details": "Add 6 unit tests for full coverage",
"effort_estimate": "2-3 hours"
},
"expected_impact": {
"risk_reduction": 3.9,
"complexity_reduction": 0,
"coverage_improvement": 100
},
"upstream_dependencies": 0,
"downstream_dependencies": 3,
"nesting_depth": 1,
"function_length": 13
}
],
"call_graph": {
"total_functions": 1523,
"entry_points": 12,
"test_functions": 456,
"max_depth": 8
},
"overall_coverage": 82.3,
"total_impact": {
"risk_reduction": 45.2,
"complexity_reduction": 12.3,
"coverage_improvement": 18.5
}
}
Markdown Output
Markdown format generates documentation-friendly reports suitable for README files, PR comments, and technical documentation.
Basic Usage
# Generate markdown report
debtmap analyze . --format markdown
# Save to documentation
debtmap analyze . --format markdown -o docs/DEBT_REPORT.md
Markdown Structure
Markdown output includes:
- Executive Summary - High-level metrics and health dashboard
- Complexity Analysis - Detailed complexity breakdown by file
- Technical Debt - Categorized debt items with priorities
- Dependencies - Module dependencies and circular references
- Recommendations - Prioritized action items
Example Markdown Output
# Debtmap Analysis Report
**Generated:** 2025-01-09 15:30:00 UTC
**Project:** /Users/dev/myproject
## Executive Summary
- **Files Analyzed:** 42
- **Total Functions:** 287
- **Average Complexity:** 6.3
- **Total Debt Items:** 15
- **Debt Score:** 156/100 ⚠️
### Health Dashboard
| Metric | Value | Status |
|--------|-------|--------|
| Complexity | 6.3 avg | ✅ Good |
| Debt Score | 156 | ⚠️ Attention |
| High Priority Items | 5 | ⚠️ Action Needed |
## Complexity Analysis
### Top 5 Complex Functions
| Function | File | Cyclomatic | Cognitive | Priority |
|----------|------|-----------|-----------|----------|
| parse_function | src/analyzers/rust.rs:245 | 18 | 24 | High |
| detect_data_clumps | src/debt/smells.rs:196 | 15 | 20 | Medium |
| analyze_dependencies | src/core/deps.rs:89 | 14 | 18 | Medium |
### Refactoring Recommendations
**src/analyzers/rust.rs:245** - `parse_function()`
- **Complexity:** Cyclomatic: 18, Cognitive: 24
- **Action:** Extract 3-5 pure functions using decompose-then-transform strategy
- **Patterns:** Decompose into logical units, then apply functional patterns
- **Benefit:** Improved testability and maintainability
## Technical Debt
### High Priority (5 items)
- **src/risk/scoring.rs:142** - TODO: Implement caching for score calculations
- **src/core/metrics.rs:89** - High complexity: cyclomatic=16
- **src/debt/patterns.rs:201** - Code duplication: 65 lines duplicated
### Medium Priority (8 items)
...
## Dependencies
### Circular Dependencies
- `risk::scoring` → `core::metrics` → `risk::scoring`
## Recommendations
1. **Refactor parse_function** (High Priority)
- Reduce complexity from 18 to <10
- Extract helper functions
- Estimated effort: 4-6 hours
2. **Add tests for scoring module** (High Priority)
- Current coverage: 35%
- Target coverage: 80%
- Estimated effort: 2-3 hours
Enhanced Markdown Features
Debtmap can generate enhanced markdown reports with additional visualizations and insights:
- Complexity distribution charts - Visual representation of complexity across codebase
- Risk heat maps - Color-coded risk matrices
- Dependency graphs - Module relationship diagrams
- Quick wins section - Low-effort, high-impact improvements
- Strategic priorities - Long-term architectural improvements
- Team guidance - Role-specific recommendations
Note: Enhanced markdown features are implemented in the codebase (
src/io/writers/enhanced_markdown/
module) but the specific flags or configuration options to enable them are not currently documented. Refer to the source code or use--help
to discover available options.
Rendering to HTML/PDF
Markdown reports can be converted to other formats:
# Generate markdown
debtmap analyze . --format markdown -o report.md
# Convert to HTML with pandoc
pandoc report.md -o report.html --standalone --css style.css
# Convert to PDF
pandoc report.md -o report.pdf --pdf-engine=xelatex
Tool Integration
CI/CD Pipelines
Debtmap JSON output integrates seamlessly with CI/CD systems.
GitHub Actions
name: Code Quality
on: [pull_request]
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install debtmap
run: cargo install debtmap
- name: Run analysis
run: |
debtmap analyze . \
--format json \
--output analysis.json \
--lcov coverage/lcov.info
- name: Check thresholds
run: |
DEBT_SCORE=$(jq '.technical_debt.items | length' analysis.json)
if [ "$DEBT_SCORE" -gt 100 ]; then
echo "❌ Debt score too high: $DEBT_SCORE"
exit 1
fi
- name: Comment on PR
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const analysis = JSON.parse(fs.readFileSync('analysis.json'));
const summary = `## Debtmap Analysis
- **Debt Items:** ${analysis.technical_debt.items.length}
- **Average Complexity:** ${analysis.complexity.summary.average_complexity}
- **High Complexity Functions:** ${analysis.complexity.summary.high_complexity_count}
`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: summary
});
GitLab CI
code_quality:
stage: test
script:
- cargo install debtmap
- debtmap analyze . --format json --output gl-code-quality.json
- |
DEBT=$(jq '.technical_debt.items | length' gl-code-quality.json)
if [ "$DEBT" -gt 50 ]; then
echo "Debt threshold exceeded"
exit 1
fi
artifacts:
reports:
codequality: gl-code-quality.json
Jenkins Pipeline
pipeline {
agent any
stages {
stage('Analyze') {
steps {
sh 'debtmap analyze . --format json -o report.json'
script {
def json = readJSON file: 'report.json'
def debtScore = json.technical_debt.items.size()
if (debtScore > 100) {
error("Debt score ${debtScore} exceeds threshold")
}
}
}
}
}
post {
always {
archiveArtifacts artifacts: 'report.json'
}
}
}
Querying JSON with jq
Common jq queries for analyzing debtmap output:
# Get total debt items
jq '.technical_debt.items | length' report.json
# Get high-priority items only
jq '.technical_debt.items[] | select(.priority == "High")' report.json
# Get functions with complexity > 10
jq '.complexity.metrics[] | select(.cyclomatic > 10)' report.json
# Calculate average complexity
jq '.complexity.summary.average_complexity' report.json
# Get all TODO items
jq '.technical_debt.items[] | select(.debt_type == "Todo")' report.json
# Get top 5 complex functions
jq '.complexity.metrics | sort_by(-.cyclomatic) | .[0:5] | .[] | {name, file, cyclomatic}' report.json
# Get files with circular dependencies
jq '.dependencies.circular[] | .cycle' report.json
# Count debt items by type
jq '.technical_debt.items | group_by(.debt_type) | map({type: .[0].debt_type, count: length})' report.json
# Get functions with 0% coverage (when using --lcov)
jq '.complexity.metrics[] | select(.coverage == 0)' report.json
# Extract file paths with high debt
jq '.technical_debt.items[] | select(.priority == "High" or .priority == "Critical") | .file' report.json | sort -u
Filtering and Transformation Examples
Python Script to Parse JSON
#!/usr/bin/env python3
import json
import sys
def analyze_debtmap_output(json_file):
with open(json_file) as f:
data = json.load(f)
# Get high-priority items
high_priority = [
item for item in data['technical_debt']['items']
if item['priority'] in ['High', 'Critical']
]
# Group by file
by_file = {}
for item in high_priority:
file = item['file']
if file not in by_file:
by_file[file] = []
by_file[file].append(item)
# Print summary
print(f"High-priority debt items: {len(high_priority)}")
print(f"Files affected: {len(by_file)}")
print("\nBy file:")
for file, items in sorted(by_file.items(), key=lambda x: -len(x[1])):
print(f" {file}: {len(items)} items")
return by_file
if __name__ == '__main__':
analyze_debtmap_output(sys.argv[1])
Shell Script for Threshold Checking
#!/bin/bash
set -e
REPORT="$1"
DEBT_THRESHOLD=100
COMPLEXITY_THRESHOLD=10
# Check debt score
DEBT_SCORE=$(jq '.technical_debt.items | length' "$REPORT")
if [ "$DEBT_SCORE" -gt "$DEBT_THRESHOLD" ]; then
echo "❌ Debt score $DEBT_SCORE exceeds threshold $DEBT_THRESHOLD"
exit 1
fi
# Check average complexity
AVG_COMPLEXITY=$(jq '.complexity.summary.average_complexity' "$REPORT")
if (( $(echo "$AVG_COMPLEXITY > $COMPLEXITY_THRESHOLD" | bc -l) )); then
echo "❌ Average complexity $AVG_COMPLEXITY exceeds threshold $COMPLEXITY_THRESHOLD"
exit 1
fi
echo "✅ All quality checks passed"
echo " Debt score: $DEBT_SCORE/$DEBT_THRESHOLD"
echo " Avg complexity: $AVG_COMPLEXITY"
Editor Integration
VS Code Tasks
Create .vscode/tasks.json
:
{
"version": "2.0.0",
"tasks": [
{
"label": "Debtmap: Analyze",
"type": "shell",
"command": "debtmap",
"args": [
"analyze",
".",
"--format",
"terminal"
],
"problemMatcher": [],
"presentation": {
"reveal": "always",
"panel": "new"
}
},
{
"label": "Debtmap: Generate Report",
"type": "shell",
"command": "debtmap",
"args": [
"analyze",
".",
"--format",
"markdown",
"-o",
"DEBT_REPORT.md"
],
"problemMatcher": []
}
]
}
Problem Matcher for VS Code
Parse debtmap output in VS Code’s Problems panel:
{
"problemMatcher": {
"owner": "debtmap",
"fileLocation": "absolute",
"pattern": {
"regexp": "^(.+?):(\\d+):(\\d+)?\\s*-\\s*(.+)$",
"file": 1,
"line": 2,
"column": 3,
"message": 4
}
}
}
Webhook Integration
Send debtmap results to webhooks for notifications:
#!/bin/bash
# Run analysis
debtmap analyze . --format json -o report.json
# Send to Slack
DEBT_SCORE=$(jq '.technical_debt.items | length' report.json)
curl -X POST "$SLACK_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d "{\"text\": \"Debtmap Analysis Complete\n• Debt Score: $DEBT_SCORE\n• High Priority: $(jq '[.technical_debt.items[] | select(.priority == "High")] | length' report.json)\"}"
# Send to custom webhook
curl -X POST "$CUSTOM_WEBHOOK_URL" \
-H 'Content-Type: application/json' \
-d @report.json
Output Filtering
Debtmap provides several flags to filter and limit output:
Note: Filtering options (
--top
,--tail
,--summary
,--filter
) apply to all output formats (terminal, JSON, and markdown). The filtered data is applied at the analysis level before formatting, ensuring consistent results across all output types.
Limiting Results
# Show only top 10 priority items
debtmap analyze . --top 10
# Show bottom 5 lowest priority items
debtmap analyze . --tail 5
Priority Filtering
# Show only high and critical priority items
debtmap analyze . --min-priority high
# Filter by specific debt categories
debtmap analyze . --filter Architecture,Testing
Available categories:
Architecture
: God objects, complexity hotspots, dead codeTesting
: Testing gaps, coverage issuesPerformance
: Resource leaks, inefficient patternsCodeQuality
: Code smells, maintainability
Grouping Output
# Group results by debt category
debtmap analyze . --group-by-category
# Combine filters for focused analysis
debtmap analyze . --filter Architecture --min-priority high --top 5
Summary Mode
# Compact tiered priority display
debtmap analyze . --summary
# Combines well with filtering
debtmap analyze . --summary --min-priority medium
Best Practices
When to Use Each Format
Use Terminal Format When:
- Developing locally and reviewing code
- Getting quick feedback on changes
- Presenting results to team members
- Exploring complexity hotspots interactively
Use JSON Format When:
- Integrating with CI/CD pipelines
- Building custom analysis tools
- Tracking metrics over time
- Programmatically processing results
- Feeding into dashboards or monitoring systems
Use Markdown Format When:
- Generating documentation
- Creating PR comments
- Sharing reports with stakeholders
- Archiving analysis results
- Producing executive summaries
Quick Reference Table
Format | Best For | Machine Readable | Human Readable | File Extension |
---|---|---|---|---|
Terminal | Development | No | Yes | .txt |
JSON | Automation | Yes | No | .json |
Markdown | Documentation | Partially | Yes | .md |
Combining Formats
Use multiple formats for comprehensive workflows:
# Generate terminal output for review
debtmap analyze .
# Generate JSON for automation
debtmap analyze . --format json -o ci-report.json
# Generate markdown for documentation
debtmap analyze . --format markdown -o docs/DEBT.md
Performance Considerations
- Terminal format: Fastest, minimal overhead
- JSON format: Fast serialization, efficient for large codebases
- Markdown format: Slightly slower due to formatting, but still performant
For very large codebases (>10,000 files), use --top
or --filter
to limit output size.
Troubleshooting
Common Issues
Colors not showing in terminal:
- Check if terminal supports ANSI colors
- Use
--plain
flag for ASCII-only output - Some CI systems may not support color codes
JSON parsing errors:
- Ensure output is complete (check for errors during analysis)
- Validate JSON with
jq
or online validators - Check for special characters in file paths
Markdown rendering issues:
- Some markdown renderers don’t support all features
- Use standard markdown for maximum compatibility
- Test with pandoc or GitHub/GitLab preview
File encoding problems:
- Ensure UTF-8 encoding for all output files
- Use
--plain
for pure ASCII output - Check locale settings (LC_ALL, LANG environment variables)
Exit Codes
IMPORTANT: Exit codes 1 and 2 are NOT YET IMPLEMENTED. Current behavior: Always returns
0
on successful analysis, regardless of threshold violations.Planned behavior includes:
0
: Success, all checks passed1
: Analysis completed, but validation thresholds exceeded2
: Error during analysis (invalid path, parsing error, etc.)
For now, use the validate
command with threshold checks to enforce quality gates:
# Use validate command for threshold enforcement
debtmap validate . --config debtmap.toml
# Or parse JSON output for threshold checking
debtmap analyze . --format json -o report.json
DEBT_SCORE=$(jq '.technical_debt.items | length' report.json)
if [ "$DEBT_SCORE" -gt 100 ]; then
echo "Debt threshold exceeded"
exit 1
fi
See Also
- Getting Started - Basic usage and examples
- Analysis Guide - Understanding metrics and scores
- Configuration - Customizing analysis behavior
Tiered Prioritization
Debtmap uses a sophisticated tiered prioritization system to surface critical architectural issues above simple testing gaps. This chapter explains the tier strategy, how to interpret tier classifications, and how to customize tier thresholds for your project.
Overview
The tiered prioritization system organizes technical debt into four distinct tiers based on impact, urgency, and architectural significance. This prevents “walls of similar-scored items” and ensures critical issues don’t get lost among minor problems.
The Four Tiers
Tier 1: Critical Architecture
Description: God Objects, God Modules, excessive complexity requiring immediate architectural attention
Priority: Must address before adding new features
Weight: 1.5x (highest priority multiplier)
Impact: High impact on maintainability and team velocity
Examples:
- Files with 15+ responsibilities
- Modules with 50+ methods
- God objects flagged by detection algorithms
- Circular dependencies affecting core modules
When to Address: Immediately, before sprint work begins. These issues compound over time and block progress.
# Focus on Tier 1 items
debtmap analyze . --filter Architecture --min-priority high
Tier 2: Complex Untested
Description: Untested code with high complexity or critical dependencies
Priority: Risk of bugs in critical paths
Weight: 1.0x (standard multiplier)
Action: Should be tested before refactoring to prevent regressions
Examples:
- Functions with cyclomatic complexity > 15 and 0% coverage
- Business logic entry points without tests
- Complex error handling without validation
When to Address: Within current sprint. Add tests before making changes.
# See Tier 2 testing gaps
debtmap analyze . --lcov coverage.lcov --filter Testing
Tier 3: Testing Gaps
Description: Untested code with moderate complexity
Priority: Improve coverage to prevent future issues
Weight: 0.7x (reduced multiplier)
Action: Add tests opportunistically or during related changes
Examples:
- Functions with cyclomatic complexity 10-15 and low coverage
- Utility functions without edge case tests
- Moderate complexity with partial coverage
When to Address: Next sprint or when touching related code.
Tier 4: Maintenance
Description: Low-complexity issues and code quality improvements
Priority: Address opportunistically during other work
Weight: 0.3x (lowest multiplier)
Action: Fix when convenient, low urgency
Examples:
- Simple functions with minor code quality issues
- TODO markers in well-tested code
- Minor duplication in test code
When to Address: During cleanup sprints or when refactoring nearby code.
Configuration
Default Tier Thresholds
[tiers]
# Tier 2 thresholds (Complex Untested)
t2_complexity_threshold = 15 # Cyclomatic complexity cutoff
t2_dependency_threshold = 10 # Dependency count cutoff
# Tier 3 thresholds (Testing Gaps)
t3_complexity_threshold = 10 # Lower complexity threshold
# Display options
show_t4_in_main_report = false # Hide Tier 4 from main output
# Tier weights
[tiers.tier_weights]
t1 = 1.5 # Critical architecture
t2 = 1.0 # Complex untested
t3 = 0.7 # Testing gaps
t4 = 0.3 # Maintenance
Customizing Tier Thresholds
Adjust thresholds to match your team’s standards:
# Stricter thresholds for high-quality codebases
[tiers]
t2_complexity_threshold = 12
t3_complexity_threshold = 8
# More lenient for legacy codebases
[tiers]
t2_complexity_threshold = 20
t3_complexity_threshold = 15
Tier Weight Customization
Adjust weights based on your priorities:
# Emphasize testing over architecture
[tiers.tier_weights]
t1 = 1.2 # Reduce architecture weight
t2 = 1.3 # Increase testing weight
t3 = 0.8
t4 = 0.3
# Focus on architecture first
[tiers.tier_weights]
t1 = 2.0 # Maximize architecture weight
t2 = 1.0
t3 = 0.5
t4 = 0.2
Use Cases
Sprint Planning
Use tiered prioritization to allocate work:
# See Tier 1 items for architectural planning
debtmap analyze . --filter Architecture --top 5
# See Tier 2/3 for testing sprint work
debtmap analyze . --filter Testing --min-priority medium
Code Review Focus
Prioritize review attention based on tiers:
- Tier 1: Architectural review required, senior dev attention
- Tier 2: Test coverage validation critical
- Tier 3: Standard review process
- Tier 4: Quick review or automated checks
Refactoring Strategy
# Phase 1: Address Tier 1 architectural issues
debtmap analyze . --filter Architecture
# Phase 2: Add tests for Tier 2 complex code
debtmap analyze . --lcov coverage.lcov --min-priority high
# Phase 3: Improve Tier 3 coverage
debtmap analyze . --lcov coverage.lcov --min-priority medium
Best Practices
- Always address Tier 1 before feature work - Architectural issues compound
- Test Tier 2 items before refactoring - Avoid regressions
- Batch Tier 3 items - Address multiple in one sprint
- Defer Tier 4 items - Only fix during cleanup or when convenient
- Track tier distribution over time - Aim to reduce Tier 1/2 counts
Interpreting Tier Output
Terminal Output
════════════════════════════════════════════
TIERED TECHNICAL DEBT REPORT
════════════════════════════════════════════
🔴 TIER 1: CRITICAL ARCHITECTURE (3 items)
1. src/services.rs - God Object (85% god score, 52 methods)
2. src/core/engine.rs - Circular dependency with parsers module
3. src/api/handlers.rs - God Module (15 responsibilities)
🟠 TIER 2: COMPLEX UNTESTED (12 items)
1. src/processing/transform.rs:145 - Complexity 18, Coverage 0%
...
🟡 TIER 3: TESTING GAPS (45 items)
...
⚪ TIER 4: MAINTENANCE (120 items) [hidden]
Use --show-t4 to display maintenance items
JSON Output
{
"tier_distribution": {
"t1_count": 3,
"t2_count": 12,
"t3_count": 45,
"t4_count": 120
},
"items": [
{
"tier": "T1_CriticalArchitecture",
"priority_weight": 1.5,
"base_score": 8.5,
"final_score": 12.75
}
]
}
Troubleshooting
Issue: Too many Tier 1 items
Solution: Lower tier weights or increase thresholds temporarily:
[tiers.tier_weights]
t1 = 1.2 # Reduce from 1.5
Issue: Not enough items in Tier 1
Solution: Check if god object detection is enabled:
[god_object_detection]
enabled = true
Issue: All items in Tier 4
Solution: Lower minimum thresholds:
[thresholds]
minimum_debt_score = 1.0
minimum_cyclomatic_complexity = 2
See Also
- Scoring Strategies - Understanding file-level vs function-level scoring
- Configuration - Complete configuration reference
- Analysis Guide - Detailed metric explanations
Scoring Strategies
Debtmap provides two complementary scoring approaches: file-level and function-level. Understanding when to use each approach helps you make better refactoring decisions and prioritize work effectively.
Overview
Different refactoring scenarios require different levels of granularity:
- File-level scoring: Identifies architectural issues and planning major refactoring initiatives
- Function-level scoring: Pinpoints specific hot spots for targeted improvements
This chapter explains both approaches, when to use each, and how to interpret the results.
File-Level Scoring
File-level scoring aggregates metrics across all functions in a file to identify architectural problems and module-level refactoring opportunities.
Formula
File Score = Size × Complexity × Coverage × Density × GodObject × FunctionScores
Where each factor is calculated as:
- Size =
sqrt(total_lines / 100)
- Complexity =
(avg_complexity / 5.0) × sqrt(total_complexity / 50.0)
- Coverage =
(1 - coverage_percent) × 2 + 1
- Density =
max(1.0, function_count / 50)
if function_count > 50 - GodObject =
2.0 + god_object_score
if detected - FunctionScores =
sum(function_scores) / 10
Factors
Size Factor: sqrt(total_lines / 100)
- Larger files have higher impact
- Square root dampens the effect to avoid over-penalizing large files
- Rationale: Refactoring a 1000-line file affects more code than a 100-line file
Complexity Factor: Combines average and total complexity
(average_cyclomatic + total_cyclomatic / function_count) / 2
- Balances per-function and aggregate complexity
- Rationale: Both concentrated complexity and spread-out complexity matter
Coverage Factor: (1 - coverage_percent) × 2 + 1
- Lower coverage increases score multiplicatively
- Range: 1.0 (100% coverage) to 3.0 (0% coverage)
- Rationale: Untested files are riskier to refactor
Density Factor: Penalizes files with excessive function count
- Triggers when function count > 50
max(1.0, function_count / 50)
- Rationale: Files with 100+ functions likely violate single responsibility
God Object Multiplier: 2.0 + god_object_score
when detected
- Applies when god object detection flags the file
- Range: 2.0 (borderline) to 3.0 (severe god object)
- Rationale: God objects need immediate architectural attention
Function Scores: sum(all_function_scores) / 10
- Normalized sum of individual function debt scores
- Provides baseline before modifiers
Use Cases
1. Planning Major Refactoring Initiatives
# Show top 10 files needing architectural refactoring
debtmap analyze . --aggregate-only --top 10
Use when:
- Planning sprint or quarterly refactoring work
- Deciding which modules to split
- Prioritizing architectural improvements
- Allocating team resources
Note: File-level scoring is enabled with the --aggregate-only
flag, which changes output to show only file-level metrics instead of function-level details.
2. Identifying Architectural Issues
File-level scoring excels at finding:
- God objects with too many responsibilities
- Files with poor cohesion
- Modules that should be split
- Files with too many functions
# Focus on architectural problems
debtmap analyze . --aggregate-only --filter Architecture
3. Breaking Up Monolithic Modules
# Find files with excessive function counts
debtmap analyze . --aggregate-only --min-problematic 50
4. Evaluating Overall Codebase Health
# Generate file-level report for executive summary
debtmap analyze . --aggregate-only --format markdown -o report.md
Aggregation Methods
Debtmap supports multiple aggregation methods for file-level scores, configurable via CLI or configuration file.
Weighted Sum (Default)
debtmap analyze . --aggregation-method weighted_sum
Or via configuration:
[aggregation]
method = "weighted_sum"
- Weights functions by complexity and coverage
- Emphasizes high-impact functions
- Best for most use cases
Simple Sum
[aggregation]
method = "sum"
- Adds all function scores directly
- Treats all functions equally
- Useful for broad overview
Logarithmic Sum
[aggregation]
method = "logarithmic_sum"
- Dampens impact of many small issues
log(1 + sum_of_scores)
- Useful for legacy codebases with many minor issues
Max Plus Average
[aggregation]
method = "max_plus_average"
- Considers worst function plus average of others
max_score × 0.6 + average_score × 0.4
- Balances worst-case and typical-case analysis
Configuration
[aggregation]
method = "weighted_sum"
min_problematic = 3 # Need 3+ problematic functions for file-level score
[god_object_detection]
enabled = true
max_methods = 20
max_fields = 15
max_responsibilities = 5
Function-Level Scoring
Function-level scoring identifies specific functions needing attention for targeted improvements.
Formula
Function Score = (Complexity × 0.35) + (Coverage × 0.50) + (Dependency × 0.15)
Final Score = Base Score × Role Multiplier
Note: These weights are configurable via the [scoring]
section in .debtmap.toml
. See Configuration below.
Metrics
Cyclomatic Complexity
- Counts decision points (if, match, loops)
- Guides test case count
Cognitive Complexity
- Measures understanding difficulty
- Accounts for nesting depth
Coverage Percentage
- Direct line coverage from LCOV
- 0% coverage = maximum urgency
Dependency Count
- Upstream callers + downstream callees
- Higher dependencies = higher impact
Role Multiplier
Functions are classified by role, and each role receives a multiplier based on its architectural importance:
- Entry points: 1.5x - Public APIs, main functions, HTTP handlers
- Pure logic / Business logic: 1.2x-1.3x - Core business rules and algorithms (multiplier increases with complexity)
- Orchestrator: 0.8x - Functions that coordinate other functions
- IO wrapper: 0.5x - Simple file/network I/O wrappers
- Pattern match: 0.6x - Functions primarily doing pattern matching
- Utility: 0.5x - Helper functions and utilities
Note: Role multipliers are configurable via the [role_multipliers]
section in .debtmap.toml
.
Use Cases
1. Identifying Specific Hot Spots
# Show top 20 functions needing attention
debtmap analyze . --top 20
Use when:
- Planning individual developer tasks
- Assigning specific refactoring work
- Identifying functions to test first
- Code review focus
2. Sprint Planning for Developers
# Get function-level tasks for this sprint
debtmap analyze . --top 10 --format json -o sprint-tasks.json
3. Writing Unit Tests
# Find untested complex functions
debtmap analyze . --lcov coverage.lcov --filter Testing --top 15
4. Targeted Performance Optimization
# Find complex hot paths
debtmap analyze . --filter Performance --context --top 10
Configuration
[scoring]
coverage = 0.50 # Weight for coverage gaps (default)
complexity = 0.35 # Weight for complexity (default)
dependency = 0.15 # Weight for dependency impact (default)
[role_multipliers]
entry_point = 1.5
business_logic = 1.2
pure_logic = 1.2
orchestrator = 0.8
io_wrapper = 0.7
utility = 0.5
When to Use Each Approach
Use File-Level Scoring When:
✅ Planning architectural refactoring ✅ Quarterly or annual planning ✅ Deciding which modules to split ✅ Executive summaries and high-level reports ✅ Team capacity planning ✅ Identifying god objects ✅ Module reorganization
Command:
debtmap analyze . --aggregate-only
Use Function-Level Scoring When:
✅ Sprint planning ✅ Individual developer task assignment ✅ Writing specific unit tests ✅ Code review preparation ✅ Pair programming sessions ✅ Daily or weekly development work ✅ Targeted hot spot fixes
Command:
debtmap analyze . --top 20
Use Both Together:
Many workflows benefit from both views:
# Step 1: Identify problematic files
debtmap analyze . --aggregate-only --top 5 -o files.json
# Step 2: Drill into specific file
debtmap analyze src/problematic/module.rs --format terminal
Comparison Examples
Example 1: God Object Detection
File-Level View:
src/services/user_service.rs - Score: 245.8
- 850 lines, 45 methods
- God Object: 78% score
- Action: Split into UserAuth, UserProfile, UserNotifications
Function-Level View:
src/services/user_service.rs:142 - authenticate_user() - Score: 8.5
src/services/user_service.rs:298 - update_profile() - Score: 7.2
src/services/user_service.rs:456 - send_notification() - Score: 6.8
Decision: File-level score (245.8) correctly identifies architectural issue. Individual functions aren’t exceptionally complex, but the file has too many responsibilities. Solution: Split the file.
Example 2: Targeted Function Fix
File-Level View:
src/parsers/expression.rs - Score: 45.2
- 320 lines, 12 functions
- No god object detected
Function-Level View:
src/parsers/expression.rs:89 - parse_complex_expression() - Score: 9.1
- Cyclomatic: 22, Cognitive: 35
- Coverage: 0%
- Action: Add tests and refactor
Decision: File as a whole is acceptable, but one function needs attention. Solution: Focus on that specific function.
Example 3: Balanced Refactoring
File-Level View:
src/analysis/scoring.rs - Score: 125.6
- 580 lines, 18 functions
- High complexity, low coverage
Function-Level View:
calculate_score() - Score: 8.8 (15% coverage)
apply_weights() - Score: 8.2 (10% coverage)
normalize_results() - Score: 7.5 (0% coverage)
Decision: Both file and functions need work. Solution: Add tests first (function-level), then consider splitting if complexity persists (file-level).
Score Normalization
Both scoring approaches normalize to a 0-10 scale for consistency.
Normalization Strategy
#![allow(unused)] fn main() { score_normalized = if raw_score < 10.0 { raw_score // Linear below 10 } else if raw_score < 100.0 { sqrt(raw_score) × 3.33 // Square root 10-100 } else { log10(raw_score) × 10.0 // Logarithmic above 100 } }
Configuration
[normalization]
linear_threshold = 10.0 # Scores below this use linear scaling (1:1 mapping)
logarithmic_threshold = 100.0 # Scores above this use logarithmic dampening
sqrt_multiplier = 3.33 # Applied to scores between linear and log thresholds
log_multiplier = 10.0 # Applied to scores above logarithmic threshold
show_raw_scores = true # Display both normalized (0-10) and raw scores in output
Explanation:
- linear_threshold: Scores below this value are mapped 1:1 (no scaling)
- logarithmic_threshold: Scores above this value are dampened logarithmically to prevent extreme values
- sqrt_multiplier: Square root scaling applied to mid-range scores (between linear and logarithmic thresholds)
- log_multiplier: Logarithmic dampening factor for very high scores
- show_raw_scores: When enabled, output includes both the normalized 0-10 score and the raw calculated score
Best Practices
Workflow Integration
Week 1: File-Level Assessment
# Identify architectural problems
debtmap analyze . --aggregate-only --top 10
Week 2-4: Function-Level Work
# Work through specific functions
debtmap analyze src/target/module.rs
Monthly: Compare Progress
debtmap compare --before baseline.json --after current.json
Team Collaboration
- Architects: Use file-level scores for strategic planning
- Tech Leads: Use both for sprint planning
- Developers: Use function-level for daily work
- QA: Use function-level for test prioritization
CI/CD Integration
# Gate: No new file-level regressions
debtmap analyze . --aggregate-only --format json -o file-scores.json
# Gate: No new critical function-level issues
debtmap analyze . --min-priority critical --format json -o critical-items.json
Troubleshooting
Issue: File-level scores seem too high
Solution: Check aggregation method:
[aggregation]
method = "logarithmic_sum" # Dampen scores
Issue: Function-level scores all similar
Solution: Adjust scoring weights to emphasize different factors:
[scoring]
coverage = 0.60 # Emphasize testing gaps more
complexity = 0.30
dependency = 0.10
Issue: Too many low-priority items
Solution: Use minimum thresholds:
[thresholds]
minimum_debt_score = 3.0
See Also
- Tiered Prioritization - Understanding tier-based classification
- Configuration - Scoring and aggregation configuration
- Analysis Guide - Detailed metric explanations
Prodigy Integration
Debtmap integrates with Prodigy to provide fully automated technical debt reduction through AI-driven workflows. This chapter explains how to set up and use Prodigy workflows to automatically refactor code, add tests, and improve codebase quality.
What is Prodigy?
Prodigy is an AI-powered workflow automation system that uses Claude to execute complex multi-step tasks. When integrated with Debtmap, it can:
- Automatically refactor high-complexity functions identified by Debtmap
- Add unit tests for untested code
- Fix code duplication by extracting shared logic
- Improve code organization by addressing architectural issues
- Validate improvements with automated testing
All changes are made in isolated git worktrees, validated with tests and linting, and only committed if all checks pass.
Benefits
Automated Debt Reduction
Instead of manually addressing each technical debt item, Prodigy can:
- Analyze Debtmap’s output
- Select high-priority items
- Generate refactoring plans
- Execute refactorings automatically
- Validate with tests
- Commit clean changes
Iterative Improvement
Prodigy supports iterative workflows:
- Run analysis → fix top items → re-analyze → fix more
- Configurable iteration count (default: 5 iterations)
- Each iteration focuses on highest-priority remaining items
Safe Experimentation
All changes happen in isolated git worktrees:
- Original branch remains untouched
- Failed attempts don’t affect main codebase
- Easy to review before merging
- Automatic cleanup after workflow
Prerequisites
Install Prodigy
# Install Prodigy CLI
cargo install prodigy
# Verify installation
prodigy --version
Configure Claude API
# Set Claude API key
export ANTHROPIC_API_KEY="your-api-key-here"
# Or in ~/.prodigy/config.toml:
[api]
anthropic_key = "your-api-key-here"
Ensure Debtmap is Installed
# Install Debtmap
cargo install debtmap
# Verify installation
debtmap --version
Quick Start
1. Initialize Workflow
Create a workflow file workflows/debtmap.yml
:
# Sequential workflow. Fix top technical debt item
# Phase 1: Generate coverage data
- shell: "just coverage-lcov"
# Phase 2: Analyze tech debt and capture baseline
- shell: "debtmap analyze . --lcov target/coverage/lcov.info --output .prodigy/debtmap-before.json --format json"
# Phase 3: Create implementation plan (PLANNING PHASE)
- claude: "/prodigy-debtmap-plan --before .prodigy/debtmap-before.json --output .prodigy/IMPLEMENTATION_PLAN.md"
capture_output: true
validate:
commands:
- claude: "/prodigy-validate-debtmap-plan --before .prodigy/debtmap-before.json --plan .prodigy/IMPLEMENTATION_PLAN.md --output .prodigy/plan-validation.json"
result_file: ".prodigy/plan-validation.json"
threshold: 75
on_incomplete:
commands:
- claude: "/prodigy-revise-debtmap-plan --gaps ${validation.gaps} --plan .prodigy/IMPLEMENTATION_PLAN.md"
max_attempts: 3
fail_workflow: false
# Phase 4: Execute the plan (IMPLEMENTATION PHASE)
- claude: "/prodigy-debtmap-implement --plan .prodigy/IMPLEMENTATION_PLAN.md"
commit_required: true
validate:
commands:
- shell: "debtmap analyze . --lcov target/coverage/lcov.info --output .prodigy/debtmap-after.json --format json"
- shell: "debtmap compare --before .prodigy/debtmap-before.json --after .prodigy/debtmap-after.json --plan .prodigy/IMPLEMENTATION_PLAN.md --output .prodigy/comparison.json --format json"
- claude: "/prodigy-validate-debtmap-improvement --comparison .prodigy/comparison.json --output .prodigy/debtmap-validation.json"
result_file: ".prodigy/debtmap-validation.json"
threshold: 75
on_incomplete:
commands:
- claude: "/prodigy-complete-debtmap-fix --gaps ${validation.gaps} --plan .prodigy/IMPLEMENTATION_PLAN.md"
commit_required: true
- shell: "just coverage-lcov"
- shell: "debtmap analyze . --lcov target/coverage/lcov.info --output .prodigy/debtmap-after.json --format json"
- shell: "debtmap compare --before .prodigy/debtmap-before.json --after .prodigy/debtmap-after.json --plan .prodigy/IMPLEMENTATION_PLAN.md --output .prodigy/comparison.json --format json"
max_attempts: 5
fail_workflow: true
# Phase 5: Run tests with automatic fixing
- shell: "just test"
on_failure:
claude: "/prodigy-debug-test-failure --output ${shell.output}"
max_attempts: 5
fail_workflow: true
# Phase 6: Run linting and formatting
- shell: "just fmt-check && just lint"
on_failure:
claude: "/prodigy-lint ${shell.output}"
max_attempts: 5
fail_workflow: true
2. Run Workflow
# Run with worktree, auto-confirm, 5 iterations
prodigy cook workflows/debtmap.yml -wyn 5
# Run with custom iteration count
prodigy cook workflows/debtmap.yml -wyn 10
# Run single iteration for testing
prodigy cook workflows/debtmap.yml -wyn 1
Command Flags:
-w
- Create an isolated git worktree for changes-y
- Auto-confirm workflow steps (skip prompts)-n 5
- Run workflow for up to 5 iterations
3. Review Results
Prodigy creates a detailed report:
📊 WORKFLOW SUMMARY
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Iterations: 5
Items Fixed: 12
Tests Added: 8
Complexity Reduced: 145 → 78 (-46%)
Coverage Improved: 45% → 72% (+27%)
✅ All validations passed
Workflow Configuration
Prodigy workflows are defined as YAML lists of steps. Each step can be either a shell
command or a claude
slash command.
Workflow Step Types
Shell Commands
Execute shell commands directly:
- shell: "cargo test"
With error handling:
- shell: "just test"
on_failure:
claude: "/prodigy-debug-test-failure --output ${shell.output}"
max_attempts: 5
fail_workflow: true
Claude Commands
Execute Claude Code slash commands:
- claude: "/prodigy-debtmap-plan --before .prodigy/debtmap-before.json --output .prodigy/IMPLEMENTATION_PLAN.md"
capture_output: true
commit_required: true
Step-Level Validation
Steps can include validation that must pass:
- claude: "/prodigy-debtmap-implement --plan .prodigy/IMPLEMENTATION_PLAN.md"
commit_required: true
validate:
commands:
- shell: "cargo test"
- shell: "cargo clippy -- -D warnings"
result_file: ".prodigy/validation.json"
threshold: 75
on_incomplete:
commands:
- claude: "/prodigy-complete-debtmap-fix --gaps ${validation.gaps} --plan .prodigy/IMPLEMENTATION_PLAN.md"
commit_required: true
max_attempts: 5
fail_workflow: true
Validation Options:
commands
: List of commands to run for validationresult_file
: JSON file containing validation resultsthreshold
: Minimum score (0-100) required to passon_incomplete
: Actions to take if validation score < thresholdmax_attempts
: Maximum retry attemptsfail_workflow
: Whether to fail entire workflow if validation never passes
Error Handling
Use on_failure
to handle command failures:
- shell: "just fmt-check && just lint"
on_failure:
claude: "/prodigy-lint ${shell.output}"
max_attempts: 5
fail_workflow: true
Error Handling Options:
claude
: Slash command to fix the failuremax_attempts
: Maximum fix attemptsfail_workflow
: If true, workflow fails after max_attempts; if false, continues to next step
Coverage Integration
Generate and use coverage data in workflows:
# Generate coverage
- shell: "just coverage-lcov"
# Use coverage in analysis
- shell: "debtmap analyze . --lcov target/coverage/lcov.info --output .prodigy/debtmap-before.json --format json"
Claude Slash Commands
Prodigy workflows use Claude Code slash commands to perform analysis, planning, and implementation. The key commands used in the debtmap workflow are:
Planning Commands
/prodigy-debtmap-plan
Creates an implementation plan for the top priority debt item.
- claude: "/prodigy-debtmap-plan --before .prodigy/debtmap-before.json --output .prodigy/IMPLEMENTATION_PLAN.md"
capture_output: true
Parameters:
--before
: Path to debtmap analysis JSON file--output
: Path to write implementation plan
/prodigy-validate-debtmap-plan
Validates that the implementation plan is complete and addresses the debt item.
- claude: "/prodigy-validate-debtmap-plan --before .prodigy/debtmap-before.json --plan .prodigy/IMPLEMENTATION_PLAN.md --output .prodigy/plan-validation.json"
Parameters:
--before
: Original debtmap analysis--plan
: Implementation plan to validate--output
: Validation results JSON (with score 0-100)
/prodigy-revise-debtmap-plan
Revises an incomplete plan based on validation gaps.
- claude: "/prodigy-revise-debtmap-plan --gaps ${validation.gaps} --plan .prodigy/IMPLEMENTATION_PLAN.md"
Parameters:
--gaps
: List of missing items from validation--plan
: Plan file to update
Implementation Commands
/prodigy-debtmap-implement
Executes the implementation plan.
- claude: "/prodigy-debtmap-implement --plan .prodigy/IMPLEMENTATION_PLAN.md"
commit_required: true
Parameters:
--plan
: Path to implementation plan
/prodigy-validate-debtmap-improvement
Validates that the implementation successfully addressed the debt item.
- claude: "/prodigy-validate-debtmap-improvement --comparison .prodigy/comparison.json --output .prodigy/debtmap-validation.json"
Parameters:
--comparison
: Debtmap comparison results (before vs after)--output
: Validation results JSON (with score 0-100)
/prodigy-complete-debtmap-fix
Completes a partial fix based on validation gaps.
- claude: "/prodigy-complete-debtmap-fix --gaps ${validation.gaps} --plan .prodigy/IMPLEMENTATION_PLAN.md"
commit_required: true
Parameters:
--gaps
: Validation gaps to address--plan
: Original implementation plan
Testing and Quality Commands
/prodigy-debug-test-failure
Automatically fixes failing tests.
- shell: "just test"
on_failure:
claude: "/prodigy-debug-test-failure --output ${shell.output}"
max_attempts: 5
Parameters:
--output
: Test failure output from shell command
/prodigy-lint
Fixes linting and formatting issues.
- shell: "just fmt-check && just lint"
on_failure:
claude: "/prodigy-lint ${shell.output}"
max_attempts: 5
Parameters:
- Shell output with linting errors
Target Selection
Target selection happens through the debtmap analysis and slash commands, not through workflow configuration:
How Targets Are Selected
- Debtmap analyzes the codebase and scores all items by complexity, coverage, and risk
- Planning command (
/prodigy-debtmap-plan
) selects the highest priority item - Implementation command (
/prodigy-debtmap-implement
) fixes that specific item - Next iteration re-analyzes and selects the next highest priority item
Factors in Prioritization
- Complexity score: Functions with cyclomatic complexity > 10
- Coverage percentage: Lower coverage increases priority
- Risk score: Complexity × (100 - coverage%)
- Debt type: Complexity, TestGap, Duplication, GodObject, DeepNesting
Customizing Target Selection
To focus on specific debt types or modules, modify the slash commands or create custom commands in .claude/commands/
Map-Reduce Workflows
Prodigy supports map-reduce workflows for processing multiple items in parallel. This is useful for large-scale refactoring tasks.
When to Use Map-Reduce
- Processing multiple independent debt items simultaneously
- Applying the same fix pattern across many files
- Large-scale codebase cleanup tasks
Map-Reduce Structure
The exact syntax for map-reduce workflows in Prodigy may differ from sequential workflows. Consult the Prodigy documentation for current map-reduce syntax and examples.
Key Concepts:
- Map phase: Process items in parallel using multiple agents
- Reduce phase: Aggregate results and ensure consistency
- Isolation: Each map agent works in its own worktree
- Validation: All changes must pass validation before merging
Iteration Strategy
How Iterations Work
When you run prodigy cook workflows/debtmap.yml -wyn 5
, the workflow executes up to 5 times:
-
Iteration 1:
- Analyze codebase with debtmap
- Select highest priority item
- Create implementation plan
- Execute plan and validate
- Run tests and linting
-
Iteration 2:
- Re-analyze codebase (scores updated based on Iteration 1 changes)
- Select next highest priority item
- Repeat plan/implement/validate cycle
-
Continue until iteration limit reached or workflow completes without finding issues
Controlling Iterations
Iterations are controlled via the -n
flag:
# Single iteration (testing)
prodigy cook workflows/debtmap.yml -wyn 1
# Standard run (5 iterations)
prodigy cook workflows/debtmap.yml -wyn 5
# Deep cleanup (10+ iterations)
prodigy cook workflows/debtmap.yml -wyn 20
What Happens Each Iteration
Each iteration runs the entire workflow from start to finish:
- Generate coverage data
- Analyze technical debt
- Create implementation plan
- Execute plan
- Validate improvement
- Run tests (with auto-fixing)
- Run linting (with auto-fixing)
The workflow continues to the next iteration automatically if all steps succeed.
Example Output
Iteration 1:
- Fixed: parse_expression() (9.2 → 5.1)
- Fixed: calculate_score() (8.8 → 4.2)
- Fixed: apply_weights() (8.5 → 5.8)
✓ Tests pass
Iteration 2:
- Fixed: normalize_results() (7.5 → 3.9)
- Fixed: aggregate_data() (7.2 → 4.1)
✓ Tests pass
Iteration 3:
- No items above threshold (6.0)
✓ Early stop
Final Results:
Items fixed: 5
Average complexity: 15.2 → 8.6
Validation
Prodigy validates changes at the workflow step level, not as a standalone configuration.
Step-Level Validation
Validation is attached to specific workflow steps:
- claude: "/prodigy-debtmap-implement --plan .prodigy/IMPLEMENTATION_PLAN.md"
commit_required: true
validate:
commands:
- shell: "debtmap analyze . --lcov target/coverage/lcov.info --output .prodigy/debtmap-after.json --format json"
- shell: "debtmap compare --before .prodigy/debtmap-before.json --after .prodigy/debtmap-after.json --plan .prodigy/IMPLEMENTATION_PLAN.md --output .prodigy/comparison.json --format json"
- claude: "/prodigy-validate-debtmap-improvement --comparison .prodigy/comparison.json --output .prodigy/debtmap-validation.json"
result_file: ".prodigy/debtmap-validation.json"
threshold: 75
on_incomplete:
commands:
- claude: "/prodigy-complete-debtmap-fix --gaps ${validation.gaps} --plan .prodigy/IMPLEMENTATION_PLAN.md"
commit_required: true
- shell: "just coverage-lcov"
- shell: "debtmap analyze . --lcov target/coverage/lcov.info --output .prodigy/debtmap-after.json --format json"
- shell: "debtmap compare --before .prodigy/debtmap-before.json --after .prodigy/debtmap-after.json --plan .prodigy/IMPLEMENTATION_PLAN.md --output .prodigy/comparison.json --format json"
max_attempts: 5
fail_workflow: true
Validation Process
- Commands run: Execute validation commands (shell or claude)
- Check result file: Read JSON file specified in
result_file
- Compare to threshold: Score must be >= threshold (0-100 scale)
- On incomplete: If score < threshold, run
on_incomplete
commands - Retry: Repeat up to
max_attempts
times - Fail or continue: If
fail_workflow: true
, stop workflow; otherwise continue
Validation Result Format
The result_file
JSON should contain:
{
"score": 85,
"passed": true,
"gaps": [],
"details": "All debt improvement criteria met"
}
Test Validation with Auto-Fix
Tests are validated with automatic fixing on failure:
- shell: "just test"
on_failure:
claude: "/prodigy-debug-test-failure --output ${shell.output}"
max_attempts: 5
fail_workflow: true
If tests fail, Prodigy automatically attempts to fix them up to 5 times before failing the workflow.
Output and Metrics
Workflow Report
{
"workflow": "debtmap-debt-reduction",
"iterations": 5,
"items_processed": 12,
"items_fixed": 10,
"items_failed": 2,
"metrics": {
"complexity_before": 145,
"complexity_after": 78,
"complexity_reduction": -46.2,
"coverage_before": 45.3,
"coverage_after": 72.1,
"coverage_improvement": 26.8
},
"changes": [
{
"file": "src/parser.rs",
"function": "parse_expression",
"before_score": 9.2,
"after_score": 5.1,
"improvements": ["Reduced complexity", "Added tests"]
}
]
}
Commit Messages
Prodigy generates descriptive commit messages:
refactor(parser): reduce complexity in parse_expression
- Extract nested conditionals to helper functions
- Add unit tests for edge cases
- Coverage: 0% → 85%
- Complexity: 22 → 8
Generated by Prodigy workflow: debtmap-debt-reduction
Iteration: 1/5
Integration with CI/CD
GitHub Actions
name: Prodigy Debt Reduction
on:
schedule:
- cron: '0 0 * * 0' # Weekly on Sunday
workflow_dispatch:
jobs:
reduce-debt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: Install Prodigy
run: cargo install prodigy
- name: Install dependencies
run: |
cargo install debtmap
cargo install just
- name: Run Prodigy workflow
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: prodigy cook workflows/debtmap.yml -wyn 5
- name: Create PR
uses: peter-evans/create-pull-request@v5
with:
title: "chore: automated debt reduction via Prodigy"
body: |
Automated technical debt reduction using Prodigy workflow.
This PR was generated by the weekly debt reduction workflow.
Review changes carefully before merging.
branch: prodigy-debt-reduction
GitLab CI
prodigy-debt-reduction:
stage: quality
rules:
- if: '$CI_PIPELINE_SOURCE == "schedule"'
script:
- cargo install prodigy
- cargo install debtmap
- cargo install just
- prodigy cook workflows/debtmap.yml -wyn 5
artifacts:
paths:
- .prodigy/debtmap-*.json
- .prodigy/comparison.json
Important CI Considerations
- API Keys: Store
ANTHROPIC_API_KEY
as a secret - Worktrees: The
-w
flag creates isolated worktrees automatically - Dependencies: Install
prodigy
,debtmap
, andjust
(or your build tool) - Timeout: CI jobs may need extended timeout for multiple iterations
- Review: Always create a PR for human review before merging automated changes
Best Practices
1. Start Small
Begin with low iteration counts:
# First run: 1 iteration to test workflow
prodigy cook workflows/debtmap.yml -wyn 1
# Standard run: 3-5 iterations
prodigy cook workflows/debtmap.yml -wyn 5
2. Focus on High-Priority Items
The debtmap analysis automatically prioritizes by:
- Complexity score (cyclomatic complexity)
- Coverage percentage (lower coverage = higher priority)
- Risk score (complexity × (100 - coverage%))
To focus on specific areas, create custom slash commands in .claude/commands/
that filter by:
- Module/file patterns
- Specific debt types (Complexity, TestGap, Duplication)
- Score thresholds
3. Validate Thoroughly
Use comprehensive validation in your workflow:
- shell: "just test"
on_failure:
claude: "/prodigy-debug-test-failure --output ${shell.output}"
max_attempts: 5
fail_workflow: true
- shell: "just fmt-check && just lint"
on_failure:
claude: "/prodigy-lint ${shell.output}"
max_attempts: 5
fail_workflow: true
4. Review Before Merging
Always review Prodigy’s changes:
# Find your worktree
ls ~/.prodigy/worktrees/
# Check changes
cd ~/.prodigy/worktrees/session-xxx
git diff main
# Review commit history
git log --oneline
# Run full test suite
cargo test --all-features
5. Monitor Progress
Track debt reduction over iterations:
# Compare before and after
debtmap compare --before .prodigy/debtmap-before.json --after .prodigy/debtmap-after.json
# View detailed metrics
cat .prodigy/comparison.json | jq
Troubleshooting
Workflow Fails to Start
Issue: “Prodigy not found” or “API key missing”
Solution:
# Install Prodigy
cargo install prodigy
# Set API key
export ANTHROPIC_API_KEY="your-key"
# Verify installation
prodigy --version
Validation Failures
Issue: Validation score below threshold
Solution: Check validation results:
# View validation details
cat .prodigy/debtmap-validation.json
# Check what gaps remain
cat .prodigy/debtmap-validation.json | jq '.gaps'
# Review comparison results
cat .prodigy/comparison.json
The workflow will automatically retry up to max_attempts
times with /prodigy-complete-debtmap-fix
.
Test Failures
Issue: Tests fail after implementation
Solution: The workflow includes automatic test fixing:
- shell: "just test"
on_failure:
claude: "/prodigy-debug-test-failure --output ${shell.output}"
max_attempts: 5
fail_workflow: true
If tests still fail after 5 attempts, review manually:
# Check test output
just test
# Review recent changes
git diff HEAD~1
No Items Processed
Issue: Workflow completes but doesn’t find debt to fix
Possible Causes:
- Codebase has very low debt scores (below selection threshold)
- Coverage data not generated properly
- Debtmap analysis found no high-priority items
Solution:
# Check debtmap analysis results
cat .prodigy/debtmap-before.json | jq '.items | sort_by(-.unified_score.final_score) | .[0:5]'
# Verify coverage was generated
ls -lh target/coverage/lcov.info
# Run debtmap manually to see what's detected
debtmap analyze . --lcov target/coverage/lcov.info
Workflow Hangs or Times Out
Issue: Workflow takes too long or appears stuck
Possible Causes:
- Large codebase with many files
- Complex refactoring requiring extensive analysis
- Network issues with Claude API
Solution:
- Reduce iteration count for testing (
-n 1
) - Check Claude API connectivity
- Monitor worktree for progress:
cd ~/.prodigy/worktrees/session-xxx && git log
Example Workflows
Full Repository Cleanup
For comprehensive debt reduction, use a higher iteration count:
# Run 10 iterations for deeper cleanup
prodigy cook workflows/debtmap.yml -wyn 10
# Run 20 iterations for major refactoring
prodigy cook workflows/debtmap.yml -wyn 20
The workflow automatically:
- Selects highest priority items each iteration
- Addresses different debt types (Complexity, TestGap, Duplication)
- Validates all changes with tests and linting
- Commits only successful improvements
Custom Workflow for Specific Focus
Create a custom workflow file for focused improvements:
workflows/add-tests.yml
- Focus on test coverage:
# Generate coverage
- shell: "just coverage-lcov"
# Analyze with focus on test gaps
- shell: "debtmap analyze . --lcov target/coverage/lcov.info --output .prodigy/debtmap-before.json --format json"
# Create plan (slash command will prioritize TestGap items)
- claude: "/prodigy-debtmap-plan --before .prodigy/debtmap-before.json --output .prodigy/IMPLEMENTATION_PLAN.md"
# ... rest of standard workflow steps
Run with:
prodigy cook workflows/add-tests.yml -wyn 5
Targeted Module Cleanup
Create a custom slash command to focus on specific modules:
.claude/commands/refactor-module.md
:
# /refactor-module
Refactor the highest complexity item in the specified module.
Arguments: --module <module_name>
... implementation details ...
Then create a workflow using this command for targeted refactoring.
See Also
- Debtmap CLI Reference - Debtmap command options
- Configuration - Debtmap configuration
- Tiered Prioritization - Understanding priority tiers
- Prodigy Documentation - Full Prodigy reference
Examples
This chapter provides practical, real-world examples of using Debtmap across different project types and workflows. All examples use current CLI syntax verified against the source code.
Quick Start: New to Debtmap? Start with Basic Rust Analysis for the simplest introduction, then explore Coverage Integration for risk-based prioritization.
Quick Navigation: For detailed explanations of all CLI options, see the CLI Reference chapter.
Overview
This chapter demonstrates:
- Language-specific analysis: Rust, Python, JavaScript/TypeScript with their respective testing tools
- CI/CD integration: GitHub Actions, GitLab CI, CircleCI with validation gates
- Output formats: Terminal, JSON, and Markdown with interpretation guidance
- Advanced features: Context-aware analysis, multi-pass processing, cache management
- Configuration patterns: Tailored settings for different project types
- Progress tracking: Using the
compare
command to validate refactoring improvements
All examples are copy-paste ready and tested against the current Debtmap implementation.
Table of Contents
- Analyzing Rust Projects
- Python Analysis
- JavaScript/TypeScript
- CI Integration
- Output Formats
- Advanced Usage
- Configuration Examples
- Compare Command
Analyzing Rust Projects
Basic Rust Analysis
Start with a simple analysis of your Rust project:
# Analyze all Rust files in current directory
debtmap analyze .
# Analyze specific directory
debtmap analyze ./src
# Analyze with custom complexity threshold
debtmap analyze ./src --threshold-complexity 15
Coverage Integration with cargo-tarpaulin
Combine complexity analysis with test coverage for risk-based prioritization:
# Generate LCOV coverage data
cargo tarpaulin --out lcov --output-dir target/coverage
# Analyze with coverage data
debtmap analyze . --lcov target/coverage/lcov.info
# Or use the shorter alias
debtmap analyze . --coverage-file target/coverage/lcov.info
What this does:
- Functions with 0% coverage and high complexity get marked as
[CRITICAL]
- Well-tested functions (>80% coverage) are deprioritized
- Shows risk reduction potential for each untested function
Custom Thresholds
Configure thresholds to match your project standards:
# Set both complexity and duplication thresholds
debtmap analyze . \
--threshold-complexity 15 \
--threshold-duplication 50
# Use preset configurations for quick setup
debtmap analyze . --threshold-preset strict # Strict standards
debtmap analyze . --threshold-preset balanced # Default balanced
debtmap analyze . --threshold-preset lenient # Lenient for legacy code
God Object Detection
Identify classes and modules with too many responsibilities:
# Standard analysis includes god object detection
debtmap analyze .
# Disable god object detection for specific run
debtmap analyze . --no-god-object
God objects are flagged with detailed metrics:
- Number of methods and fields
- Responsibility count (grouped by naming patterns)
- God object score (0-100%)
- Recommendations for splitting
Filtering and Focusing
# Analyze only Rust files
debtmap analyze . --languages rust
# Focus on architecture issues (god objects, complexity)
debtmap analyze . --filter Architecture
# Focus on testing gaps
debtmap analyze . --filter Testing
# Filter by multiple categories
debtmap analyze . --filter Architecture,Testing
# Show only top 10 issues
debtmap analyze . --top 10
# Show only high-priority items
debtmap analyze . --min-priority high
Valid filter categories:
Architecture
- God objects, high complexity, structural issuesTesting
- Test coverage gaps, untested critical codeDuplication
- Code duplication and similar patternsMaintainability
- Long functions, deep nesting, readability issues
Output Formats
# JSON output for CI integration
debtmap analyze . --format json --output report.json
# Markdown report
debtmap analyze . --format markdown --output DEBT_REPORT.md
# Terminal output (default) - prettified
debtmap analyze .
Multi-Pass Analysis
For deeper analysis with context awareness:
# Enable context-aware analysis with multiple providers
debtmap analyze . \
--context \
--context-providers critical_path,dependency,git_history
# Multi-pass analysis with attribution
debtmap analyze . --multi-pass --attribution
Complete CI Example
This is from Debtmap’s own .github/workflows/debtmap.yml
:
# 1. Install cargo-tarpaulin
cargo install cargo-tarpaulin
# 2. Build debtmap
cargo build --release
# 3. Generate coverage
cargo tarpaulin --config .tarpaulin.toml --out Lcov --timeout 300
# 4. Run validation with coverage
./target/release/debtmap validate . \
--coverage-file target/coverage/lcov.info \
--format json \
--output debtmap-report.json
Python Analysis
Basic Python Analysis
# Analyze Python files only
debtmap analyze . --languages python
# Analyze specific Python directory
debtmap analyze src --languages python
Coverage Integration with pytest
Generate coverage and analyze risk:
# Generate LCOV coverage with pytest
pytest --cov --cov-report=lcov
# Analyze with coverage data
debtmap analyze . \
--languages python \
--lcov coverage.lcov
Python-Specific Patterns
# Focus on testing gaps in Python code
debtmap analyze . \
--languages python \
--filter Testing
# Find god objects in Python modules
debtmap analyze . \
--languages python \
--filter Architecture
Example Configuration for Python Projects
Create .debtmap.toml
:
[languages]
enabled = ["python"]
[thresholds]
complexity = 12
max_function_lines = 40
[ignore]
patterns = [
"**/*_test.py",
"tests/**",
".venv/**",
"**/__pycache__/**",
]
[god_object]
enabled = true
max_methods = 15
max_responsibilities = 4
JavaScript/TypeScript
Analyzing JS/TS Projects
# Analyze JavaScript and TypeScript
debtmap analyze . --languages javascript,typescript
# TypeScript only
debtmap analyze . --languages typescript
Coverage Integration with Jest
# Generate LCOV with Jest
jest --coverage --coverageReporters=lcov
# Analyze with coverage
debtmap analyze . \
--languages javascript,typescript \
--lcov coverage/lcov.info
Node.js Project Patterns
# Exclude node_modules and focus on source
debtmap analyze src --languages javascript,typescript
# With custom complexity thresholds for JS
debtmap analyze . \
--languages javascript,typescript \
--threshold-complexity 10
TypeScript Configuration Example
Create .debtmap.toml
:
[languages]
enabled = ["typescript", "javascript"]
[thresholds]
complexity = 10
max_function_lines = 50
[ignore]
patterns = [
"node_modules/**",
"**/*.test.ts",
"**/*.spec.ts",
"dist/**",
"build/**",
"**/*.d.ts",
]
Monorepo Analysis
# Analyze specific package
debtmap analyze packages/api --languages typescript
# Analyze all packages, grouped by category
debtmap analyze packages \
--languages typescript \
--group-by-category
CI Integration
GitHub Actions
Complete workflow example (from .github/workflows/debtmap.yml
):
name: Debtmap
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
validate:
name: Technical Debt Validation
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Cache cargo dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
- name: Install cargo-tarpaulin
run: |
if ! command -v cargo-tarpaulin &> /dev/null; then
cargo install cargo-tarpaulin
else
echo "cargo-tarpaulin already installed"
fi
- name: Build debtmap
run: cargo build --release
- name: Generate coverage data
run: cargo tarpaulin --config .tarpaulin.toml --out Lcov --timeout 300
- name: Run debtmap validation with coverage
run: |
if [ -f "target/coverage/lcov.info" ]; then
./target/release/debtmap validate . --coverage-file target/coverage/lcov.info --format json --output debtmap-report.json
else
echo "Warning: LCOV file not found, running validation without coverage data"
./target/release/debtmap validate . --format json --output debtmap-report.json
fi
- name: Upload debtmap report and coverage
if: always()
uses: actions/upload-artifact@v4
with:
name: debtmap-analysis-artifacts
path: |
debtmap-report.json
target/coverage/lcov.info
retention-days: 7
GitLab CI
debtmap:
stage: quality
image: rust:latest
script:
# Install debtmap
- cargo install debtmap
# Run tests with coverage
- cargo install cargo-tarpaulin
- cargo tarpaulin --out Lcov
# Validate with debtmap
- debtmap validate .
--coverage-file cobertura.xml
--format json
--output debtmap-report.json
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: cobertura.xml
paths:
- debtmap-report.json
expire_in: 1 week
CircleCI
version: 2.1
jobs:
debtmap:
docker:
- image: cimg/rust:1.75
steps:
- checkout
- run:
name: Install debtmap
command: cargo install debtmap
- run:
name: Generate coverage
command: |
cargo install cargo-tarpaulin
cargo tarpaulin --out Lcov
- run:
name: Run debtmap
command: |
debtmap validate . \
--coverage-file lcov.info \
--format json \
--output debtmap.json
- store_artifacts:
path: debtmap.json
workflows:
version: 2
build:
jobs:
- debtmap
Using debtmap validate for PR Gates
# Fail build if thresholds are exceeded
debtmap validate . --coverage-file lcov.info
# With custom thresholds
debtmap validate . \
--coverage-file lcov.info \
--threshold-complexity 15
# Exit code 0 if passing, 1 if failing
Compare Command in CI
Track technical debt trends over time:
# Generate baseline (on main branch)
debtmap analyze . --format json --output baseline.json
# After PR changes
debtmap analyze . --format json --output current.json
# Compare and fail if regressions detected
debtmap compare \
--before baseline.json \
--after current.json \
--format json
Output Formats
Terminal Output (Default)
The default terminal output is prettified with colors and priorities:
debtmap analyze . --lcov coverage.lcov --top 3
Example output:
════════════════════════════════════════════
PRIORITY TECHNICAL DEBT FIXES
════════════════════════════════════════════
🎯 TOP 3 RECOMMENDATIONS (by unified priority)
#1 SCORE: 8.9 [CRITICAL]
├─ TEST GAP: ./src/analyzers/rust.rs:38 parse_function()
├─ ACTION: Add 6 unit tests for full coverage
├─ IMPACT: Full test coverage, -3.7 risk
├─ COMPLEXITY: cyclomatic=6, cognitive=8, nesting=2, lines=32
├─ DEPENDENCIES: 0 upstream, 11 downstream
└─ WHY: Business logic with 0% coverage, manageable complexity
📊 TOTAL DEBT SCORE: 4907
📈 OVERALL COVERAGE: 67.12%
JSON Output
Machine-readable format for CI/CD integration:
debtmap analyze . --format json --output report.json
Using JSON output programmatically:
# Extract total debt score
debtmap analyze . --format json | jq '.total_debt_score'
# Count critical items
debtmap analyze . --format json | jq '[.items[] | select(.unified_score.final_score >= 8)] | length'
# Get top 5 functions by score
debtmap analyze . --format json | jq '.items | sort_by(-.unified_score.final_score) | .[0:5] | .[].location'
# Extract all test gap items
debtmap analyze . --format json | jq '[.items[] | select(.debt_type == "TestGap")]'
Structure:
{
"items": [
{
"location": {
"file": "src/main.rs",
"function": "process_data",
"line": 42
},
"debt_type": "TestGap",
"unified_score": {
"complexity_factor": 3.2,
"coverage_factor": 10.0,
"dependency_factor": 2.5,
"role_multiplier": 1.2,
"final_score": 9.4
},
"function_role": "BusinessLogic",
"recommendation": {
"action": "Add unit tests",
"details": "Add 6 unit tests for full coverage",
"effort_estimate": "2-3 hours"
},
"expected_impact": {
"risk_reduction": 3.9,
"complexity_reduction": 0,
"coverage_improvement": 100
}
}
],
"overall_coverage": 67.12,
"total_debt_score": 4907
}
Markdown Report
debtmap analyze . --format markdown --output DEBT_REPORT.md
Great for documentation or PR comments.
Understanding Output Formats
# JSON output (default is legacy format)
debtmap analyze . --format json
# Unified JSON format (alternative to legacy)
debtmap analyze . --format json --output-format unified
# Legacy JSON format (default, for backward compatibility)
debtmap analyze . --format json --output-format legacy
# Output format options: terminal, json, markdown
debtmap analyze . --format terminal
Advanced Usage
Context-Aware Analysis
Enable advanced context providers for more accurate prioritization:
# Enable all context providers
debtmap analyze . \
--context \
--context-providers critical_path,dependency,git_history
# Disable specific providers
debtmap analyze . \
--context \
--disable-context git_history
Multi-Pass Analysis
# Multi-pass with attribution tracking
debtmap analyze . --multi-pass --attribution
# Shows which functions contribute to which patterns
Cache Management
# Show cache statistics
debtmap cache stats
# Clear cache for current project
debtmap cache clear
# Prune old cache entries
debtmap cache prune --max-age-days 7
Aggregation Methods
# Use logarithmic sum for aggregation
debtmap analyze . --aggregation-method logarithmic_sum
# Standard sum (default)
debtmap analyze . --aggregation-method sum
Filtering and Grouping
# Group results by debt category
debtmap analyze . --group-by-category
# Filter specific categories
debtmap analyze . --filter Architecture,Testing
# Show only high-priority items
debtmap analyze . --min-priority high --top 10
Verbosity Levels
# Level 1: Show main score factors
debtmap analyze . -v
# Level 2: Show detailed calculations
debtmap analyze . -vv
# Level 3: Show all debug information
debtmap analyze . -vvv
# Long form also available
debtmap analyze . --verbose
# Show macro expansion details (Rust)
debtmap analyze . --verbose-macro-warnings --show-macro-stats
Parallel Processing Control
# Use 8 parallel jobs
debtmap analyze . --jobs 8
# Disable parallel processing
debtmap analyze . --no-parallel
Configuration Examples
Basic Configuration
Create .debtmap.toml
:
[thresholds]
complexity = 15
duplication = 25
max_function_lines = 50
max_nesting_depth = 4
[languages]
enabled = ["rust", "python"]
[ignore]
patterns = [
"tests/**/*",
"**/*.test.rs",
"target/**",
]
Entropy-Based Complexity
[entropy]
enabled = true
weight = 0.5
use_classification = true
pattern_threshold = 0.7
entropy_threshold = 0.4
branch_threshold = 0.8
max_combined_reduction = 0.3
This reduces false positives for repetitive code patterns.
Custom Scoring Weights
[scoring]
coverage = 0.40 # Test coverage gaps
complexity = 0.40 # Code complexity
dependency = 0.20 # Dependency criticality
God Object Detection Tuning
[god_object]
enabled = true
max_methods = 20
max_fields = 15
max_responsibilities = 5
External API Configuration
For libraries (not CLI tools):
[external_api]
detect_external_api = true
api_functions = [
"parse",
"Parser::new",
"client::connect",
]
api_files = [
"src/lib.rs",
"src/api.rs",
"src/public/*.rs",
]
Complete Multi-Language Configuration
[thresholds]
complexity = 12
duplication = 30
max_file_lines = 400
max_function_lines = 40
minimum_debt_score = 1.0
minimum_cyclomatic_complexity = 2
[entropy]
enabled = true
weight = 0.5
[scoring]
coverage = 0.40
complexity = 0.40
dependency = 0.20
[languages]
enabled = ["rust", "python", "javascript", "typescript"]
[ignore]
patterns = [
# Tests
"tests/**/*",
"**/*.test.*",
"**/*_test.*",
# Build artifacts
"target/**",
"dist/**",
"build/**",
"node_modules/**",
# Python
".venv/**",
"**/__pycache__/**",
# Generated code
"*.generated.*",
"*.pb.*",
]
[god_object]
enabled = true
max_methods = 18
max_fields = 12
Compare Command
The compare
command helps validate that refactoring achieved its goals.
Basic Comparison Workflow
# 1. Generate baseline before refactoring
debtmap analyze . --format json --output before.json
# 2. Make your code improvements
# ... refactor, add tests, etc ...
# 3. Generate new analysis
debtmap analyze . --format json --output after.json
# 4. Compare and verify improvements
debtmap compare --before before.json --after after.json
Target-Specific Comparison
Focus on whether a specific function improved:
# Target format: file:function:line
debtmap compare \
--before before.json \
--after after.json \
--target-location src/main.rs:process_data:100
Using with Implementation Plans
Extract target automatically from plan files:
# If IMPLEMENTATION_PLAN.md contains:
# **Target**: src/parser.rs:parse_expression:45
debtmap compare \
--before before.json \
--after after.json \
--plan IMPLEMENTATION_PLAN.md
Output Formats
# JSON output (default)
debtmap compare --before before.json --after after.json
# Terminal output (explicit)
debtmap compare \
--before before.json \
--after after.json \
--format terminal
# JSON for CI integration (explicit output file)
debtmap compare \
--before before.json \
--after after.json \
--format json \
--output comparison.json
# Markdown report
debtmap compare \
--before before.json \
--after after.json \
--format markdown \
--output COMPARISON.md
Interpreting Results
Target Status:
- Resolved: Function no longer appears (complexity reduced below threshold)
- Improved: Metrics improved (complexity down, coverage up)
- Unchanged: No significant change
- Regressed: Metrics got worse
- Not Found: Target not found in baseline
Overall Trend:
- Improving: More items resolved/improved than regressed
- Stable: No significant changes
- Regressing: New critical debt introduced
Example Output:
Target Status: Resolved ✅
- src/parser.rs:parse_expression:45 reduced from complexity 22 to 8
- Coverage improved from 0% to 85%
Overall Trend: Improving
- 3 items resolved
- 2 items improved
- 0 regressions
- Total debt score: 450 → 285 (-37%)
CI Integration
Use in pull request validation:
# In CI script
debtmap compare \
--before baseline.json \
--after current.json \
--format json | jq -e '.overall_trend == "Improving"'
# Exit code 0 if improving, 1 otherwise
Tips and Best Practices
- Start Simple: Begin with basic analysis, add coverage later
- Use Filters: Focus on one category at a time (Architecture, Testing)
- Iterate: Run analysis, fix top items, repeat
- CI Integration: Automate validation in your build pipeline
- Track Progress: Use
compare
command to validate improvements - Configure Thresholds: Adjust to match your team’s standards
- Leverage Coverage: Always include coverage data for accurate risk assessment
Next Steps
- CLI Reference - Complete CLI documentation
- Analysis Guide - Understanding analysis results
- Configuration - Advanced configuration options
Troubleshooting
Common issues and solutions for using debtmap effectively.
Quick Fixes for Common Issues
If you’re experiencing problems, try these first:
- Analysis is slow: Check
--cache-stats
, ensure caching is enabled, adjust threads with-j
- Parse errors: Use
--semantic-off
for faster fallback mode or exclude problematic files - No output: Increase verbosity with
-v
or lower--min-priority
- Cache corruption: Run with
--clear-cache
to rebuild - Inconsistent results: Check if coverage file changed or context providers are enabled
Common Issues
Parse Errors
Problem: Encountering “Parse error in file:line:column” messages
Causes:
- Unsupported language syntax or version
- Complex macro expansions (Rust)
- Type inference edge cases (Python, TypeScript)
Solutions:
# Try fallback mode without semantic analysis
debtmap --semantic-off
# For Rust macro issues, see detailed warnings
debtmap --verbose-macro-warnings --show-macro-stats
# Exclude specific problematic files
# Add to .debtmap/config.toml:
# exclude = ["path/to/problematic/file.rs"]
Out of Memory Errors
Problem: Analysis crashes or runs out of memory on large codebases
Solutions:
# Limit parallel processing
debtmap --jobs 2
# Disable parallel processing entirely
debtmap --no-parallel
# Test with limited files first
debtmap --max-files 100
# Analyze subdirectories separately
debtmap path/to/subset
Performance Issues
Problem: Analysis takes too long to complete
Solutions:
# Check cache statistics
debtmap --cache-stats
# Ensure caching is enabled (it is by default)
# If cache was disabled, remove --no-cache flag
# Use all available CPU cores
debtmap --jobs 0
# Try faster fallback mode (less accurate)
debtmap --semantic-off
# Use plain output for faster terminal rendering
debtmap --plain
See Performance Tips for detailed optimization strategies.
Cache Corruption
Problem: Getting “Cache error” messages or stale results
Solutions:
# Clear cache and rebuild
debtmap --clear-cache
# Force cache rebuild
debtmap --force-cache-rebuild
# Check cache status
debtmap --cache-stats
# Use different cache location
debtmap --cache-location /path/to/cache
See Cache Troubleshooting for more details.
File Permission Errors
Problem: “File system error” when accessing files
Solutions:
- Ensure you have read permissions for all source files
- Check that the project directory is accessible
- Verify cache directory is writable (default:
.debtmap/cache
) - Use
--cache-location
to specify an accessible cache directory
Git History Errors
Problem: Errors when using git_history
context provider
Causes:
- Not running in a git repository
- Git history not available for files
- Insufficient git permissions
Solutions:
# Disable git_history context provider
debtmap --context --disable-context git_history
# Disable all context providers
debtmap --no-context-aware
# Check if in git repository
git status
Coverage File Issues
Problem: Coverage file not being processed or causing errors
Causes:
- Non-LCOV format coverage file
- Malformed coverage data
- Path mismatches between coverage and source files
Solutions:
# Verify coverage file format (must be LCOV)
head coverage.info
# Check coverage file path
debtmap --coverage-file path/to/coverage.info -v
# Ensure paths in coverage file match source paths
# Coverage paths are relative to project root
Threshold and Preset Confusion
Problem: Unexpected filtering or priority levels
Solutions:
# Check what threshold preset does
debtmap --threshold-preset strict --help
# Override specific thresholds
debtmap --min-priority 3
# See all items regardless of thresholds
debtmap --min-priority 0
# Use category filters instead
debtmap --filter "complexity,debt"
JSON Format Issues
Problem: JSON output parsing errors or unexpected structure
Solutions:
# Use unified JSON format (consistent structure)
debtmap --format json --output-format unified
# Legacy format (default, uses {File: {...}} structure)
debtmap --format json --output-format legacy
# Validate JSON output
debtmap --format json | jq .
# Write to file for easier inspection
debtmap --format json --output results.json
Context Provider Errors
Problem: Errors with critical_path, dependency, or git_history providers
Solutions:
# Enable specific providers only
debtmap --context --context-providers critical_path,dependency
# Disable problematic provider
debtmap --context --disable-context git_history
# Disable context-aware filtering
debtmap --no-context-aware
# Check context provider details
debtmap --context -vvv
See Context Provider Troubleshooting for details.
Debug Mode
Use verbosity flags to diagnose issues and understand analysis behavior.
Verbosity Levels
# Level 1: Show main score factors
debtmap -v
# Level 2: Show detailed calculations
debtmap -vv
# Level 3: Show all debug information
debtmap -vvv
What each level shows:
-v
: Score breakdowns, main contributing factors-vv
: Detailed metric calculations, file processing-vvv
: Full debug output, context provider details, cache operations
Diagnostic Options
# Show macro parsing warnings (Rust)
debtmap --verbose-macro-warnings
# Show macro expansion statistics (Rust)
debtmap --show-macro-stats
# Disable semantic analysis (fallback mode)
debtmap --semantic-off
# Validate LOC consistency
debtmap --validate-loc
# Show cache statistics
debtmap --cache-stats
Debugging Score Calculations
# Use verbosity levels to see score breakdown
debtmap -v # Shows score factors
# See how coverage affects scores
debtmap --coverage-file coverage.info -v
# See how context affects scores
debtmap --context --context-providers critical_path -v
Example Debug Session
# Step 1: Run with verbosity to see what's happening
debtmap -vv
# Step 2: Check cache stats
debtmap --cache-stats
# Step 3: Try without semantic analysis
debtmap --semantic-off -v
# Step 4: Check specific file
debtmap path/to/file.rs -vvv
# Step 5: Validate results
debtmap --validate-loc
Performance Tips
Optimize debtmap analysis speed and resource usage.
Parallel Processing
# Use all CPU cores (default)
debtmap --jobs 0
# Limit to 4 threads
debtmap --jobs 4
# Disable parallel processing (debugging)
# Note: --no-parallel is equivalent to --jobs 1 (single-threaded)
debtmap --no-parallel
When to adjust parallelism:
- Use
--jobs 0
(default): Maximum performance on dedicated machine - Use
--jobs N
: Limit resource usage while other tasks run - Use
--no-parallel
: Debugging concurrency issues
Caching Strategies
Caching is enabled by default and provides the biggest performance improvement.
Note: The --cache
flag (to enable caching) is deprecated and hidden. Caching is now always enabled by default; use --no-cache
to disable it.
# Check cache effectiveness
debtmap --cache-stats
# Clear cache if corrupted
debtmap --clear-cache
# Force cache rebuild
debtmap --force-cache-rebuild
# Disable cache (not recommended)
debtmap --no-cache
Cache locations:
# Local cache (default): .debtmap/cache
debtmap
# Shared cache for multiple projects
debtmap --cache-location ~/.cache/debtmap
# Migrate existing cache to shared location
debtmap --migrate-cache
# Set via environment variable
export DEBTMAP_CACHE_DIR=~/.cache/debtmap
debtmap
Cache best practices:
- Use shared cache for multiple similar projects
- Monitor cache size with
--cache-stats
periodically - Clear cache after major refactorings
- Use local cache for project-specific configurations
Analysis Optimizations
# Fast mode: disable semantic analysis
debtmap --semantic-off
# Plain output: faster terminal rendering
debtmap --plain
# Limit files for testing
debtmap --max-files 100
# Analyze subdirectory only
debtmap src/specific/module
# Reduce output with filters
debtmap --min-priority 4 --top 20
Performance Comparison
Configuration | Speed | Accuracy |
---|---|---|
Default (cached) | Fast | High |
--no-cache | Slow | High |
--semantic-off | Fastest | Medium |
--no-parallel | Slowest | High |
--jobs 4 | Medium | High |
Monitoring Performance
# Time analysis
time debtmap
# Check cache hit rate
debtmap --cache-stats
# Profile with verbosity
debtmap -vv 2>&1 | grep "processed in"
Cache Troubleshooting
Detailed guidance for cache-related issues.
Check Cache Status
# View cache statistics
debtmap --cache-stats
# Sample output:
# Cache location: .debtmap/cache
# Cache entries: 1,234
# Cache size: 45.2 MB
# Hit rate: 87.3%
Clear Corrupted Cache
# Clear all cache entries
debtmap --clear-cache
# Force rebuild on next run
debtmap --force-cache-rebuild
# Manual cache deletion
rm -rf .debtmap/cache
# or for shared cache:
rm -rf ~/.cache/debtmap
Cache Location Management
# Use local cache (default)
debtmap
# Cache at: .debtmap/cache
# Use shared cache
debtmap --cache-location ~/.cache/debtmap
# Set permanently via environment
export DEBTMAP_CACHE_DIR=~/.cache/debtmap
debtmap
# Migrate existing cache
debtmap --migrate-cache
Cache Strategies
Local cache (.debtmap/cache
):
- Pros: Isolated per project, automatically managed
- Cons: Duplicates across projects
Shared cache (~/.cache/debtmap
):
- Pros: Shared across projects, saves disk space
- Cons: Requires manual management, may mix unrelated projects
Cache Consistency
# Validate LOC consistency
debtmap --validate-loc
# Cache automatically invalidates on file changes
# Uses file hashes to detect modifications
# Force fresh analysis
debtmap --no-cache
Cache Size Monitoring
# Check cache size
debtmap --cache-stats
# Clean up old entries (manual)
# No automatic cleanup - manage cache size manually
# Consider clearing cache periodically for large projects
Context Provider Troubleshooting
Diagnose and fix issues with context providers (critical_path, dependency, git_history).
Enable Context Analysis
# Enable with default providers
debtmap --context
# Or use explicit flag
debtmap --enable-context
# Specify specific providers
debtmap --context --context-providers critical_path,dependency,git_history
Disable Specific Providers
# Disable git_history only
debtmap --context --disable-context git_history
# Disable multiple providers
debtmap --context --disable-context git_history,dependency
# Disable context-aware filtering
debtmap --no-context-aware
Git History Provider Issues
Problem: “Git history error” when running analysis
Causes:
- Not in a git repository
- No git history for files
- Git not installed or accessible
Solutions:
# Verify in git repository
git status
# Disable git_history provider
debtmap --context --disable-context git_history
# Initialize git repo if needed
git init
Dependency Provider Issues
Problem: “Dependency error” or incomplete dependency graph
Causes:
- Complex import structures
- Circular dependencies
- Unsupported dependency patterns
Solutions:
# Disable dependency provider
debtmap --context --disable-context dependency
# Try with verbosity to see details
debtmap --context -vvv
# Use without context
debtmap
Critical Path Provider Issues
Problem: Critical path analysis fails or produces unexpected results
Causes:
- Invalid call graph
- Missing function definitions
- Complex control flow
Solutions:
# Disable critical_path provider
debtmap --context --disable-context critical_path
# Try with semantic analysis disabled
debtmap --context --semantic-off
# Debug with verbosity
debtmap --context --context-providers critical_path -vvv
Context Impact on Scoring
Context providers add additional risk factors to scoring:
# See context contribution to scores
debtmap --context -v
# Compare with and without context
debtmap --output baseline.json
debtmap --context --output with_context.json
debtmap compare --before baseline.json --after with_context.json
Performance Impact
Context analysis adds processing overhead:
# Faster: no context
debtmap
# Slower: with all context providers
debtmap --context --context-providers critical_path,dependency,git_history
# Medium: selective providers
debtmap --context --context-providers dependency
Debug Context Providers
# See detailed context provider output
debtmap --context -vvv
# Check which providers are active
debtmap --context -v | grep "context provider"
Advanced Analysis Troubleshooting
Advanced CLI flags for specialized analysis scenarios.
Multi-Pass Analysis
Flag: --multi-pass
Multi-pass analysis performs multiple iterations to refine results.
# Enable multi-pass analysis
debtmap --multi-pass
# Useful for complex projects with intricate dependencies
# May increase analysis time but improve accuracy
When to use:
- Complex dependency graphs
- Large codebases with deep nesting
- When single-pass results seem incomplete
Attribution Output
Flag: --attribution
Shows attribution information for detected issues.
# Enable attribution output
debtmap --attribution
# Combine with verbosity for details
debtmap --attribution -v
Troubleshooting:
- Requires git history provider for author information
- May slow down analysis
- Use
--disable-context git_history
if causing errors
Aggregation Methods
Flag: --aggregation-method <method>
Controls how results are aggregated across files.
# Available aggregation methods:
debtmap --aggregation-method weighted_sum # (default)
debtmap --aggregation-method sum
debtmap --aggregation-method logarithmic_sum
debtmap --aggregation-method max_plus_average
Common issues:
- Different methods produce different result structures
- Choose method based on your reporting needs
- Use consistent method for comparison over time
Minimum Problematic Threshold
Flag: --min-problematic <number>
Sets the minimum score for an item to be considered problematic.
# Default threshold
debtmap --min-problematic 3
# More strict (show more issues)
debtmap --min-problematic 1
# Less strict (show only serious issues)
debtmap --min-problematic 5
Relationship to other filters:
- Works alongside
--min-priority
- Filters at analysis level vs display level
- Lower values = more issues shown
God Object Detection
Flag: --no-god-object
Disables god object (large class/module) detection.
# Disable god object detection
debtmap --no-god-object
# Useful if false positives on legitimately large modules
# Or if your architecture uses centralized classes
When to use:
- False positives on framework files
- Intentional large aggregator classes
- Reducing noise in results
Detail Level Control
Flag: --detail-level <level>
Controls the level of detail in analysis output.
# Available detail levels:
debtmap --detail-level summary # High-level overview only
debtmap --detail-level standard # (default) Balanced detail
debtmap --detail-level comprehensive # Detailed analysis
debtmap --detail-level debug # Full debug information
When to use:
summary
: Quick overview for large codebasesstandard
: Default, appropriate for most use casescomprehensive
: Deep dive into specific issuesdebug
: Troubleshooting analysis behavior
Aggregation Control
Flags: --aggregate-only
, --no-aggregation
Control file-level score aggregation.
# Show only aggregated file-level scores
debtmap --aggregate-only
# Disable file-level aggregation entirely
debtmap --no-aggregation
# Default: show both individual items and file aggregates
debtmap
Use cases:
--aggregate-only
: Focus on file-level technical debt--no-aggregation
: See individual functions/classes only- Default: Full picture with both levels
Combining Advanced Flags
# Comprehensive analysis with all features
debtmap --multi-pass --attribution --context -vv
# Minimal filtering for exploration
debtmap --min-problematic 1 --min-priority 0 --no-god-object
# Performance-focused advanced analysis
debtmap --multi-pass --jobs 8 --cache-location ~/.cache/debtmap
# Summary view with aggregated scores
debtmap --detail-level summary --aggregate-only
Error Messages Reference
Understanding common error messages and how to resolve them.
File System Errors
Message: File system error: Permission denied
Meaning: Cannot read file or directory due to permissions
Solutions:
- Check file permissions:
ls -la <file>
- Ensure user has read access
- Verify cache directory is writable
- Use
--cache-location
for accessible directory
Message: File system error: No such file or directory
Meaning: File or directory does not exist
Solutions:
- Verify path is correct
- Check current working directory:
pwd
- Use absolute paths if needed
- Ensure files weren’t moved or deleted
Parse Errors
Message: Parse error in file.rs:line:column: unexpected token
Meaning: Syntax debtmap cannot parse
Solutions:
# Try fallback mode
debtmap --semantic-off
# For Rust macros
debtmap --verbose-macro-warnings --show-macro-stats
# Exclude problematic file
# In .debtmap/config.toml:
# exclude = ["path/to/file.rs"]
Analysis Errors
Message: Analysis error: internal analysis failure
Meaning: Internal error during analysis phase
Solutions:
# Try fallback mode
debtmap --semantic-off
# Report with debug info
debtmap -vvv 2>&1 | tee error.log
# Isolate problem file
debtmap --max-files 1 path/to/suspected/file
Configuration Errors
Message: Configuration error: invalid config value
Meaning: Invalid configuration in .debtmap/config.toml
or CLI
Solutions:
- Check
.debtmap/config.toml
syntax - Validate TOML format:
cat .debtmap/config.toml
- Review CLI flag values
- Check for typos in flag names
Cache Errors
Message: Cache error: corrupted cache entry
Meaning: Cache data is invalid or corrupted
Solutions:
# Clear cache
debtmap --clear-cache
# Force rebuild
debtmap --force-cache-rebuild
# Use different cache location
debtmap --cache-location /tmp/debtmap-cache
Validation Errors
Message: Validation error: threshold validation failed
Meaning: Threshold configuration is invalid
Solutions:
- Check threshold values in config
- Ensure
--min-priority
is in valid range (0-10) - Verify threshold preset exists
- Use
--threshold-preset
with valid preset name
Dependency Errors
Message: Dependency error: cannot resolve dependency graph
Meaning: Cannot build dependency relationships
Solutions:
# Disable dependency provider
debtmap --context --disable-context dependency
# Try without context
debtmap
# Debug with verbosity
debtmap -vvv
Concurrency Errors
Message: Concurrency error: parallel processing failure
Meaning: Error during parallel execution
Solutions:
# Disable parallel processing
debtmap --no-parallel
# Reduce thread count
debtmap --jobs 1
# Report issue with debug output
debtmap -vvv 2>&1 | tee error.log
Unsupported Errors
Message: Unsupported: feature not available for <language>
Meaning: Language or construct not supported
Solutions:
- Use supported languages: Rust, Python, JavaScript, TypeScript
- Check if language is enabled in config
- Some advanced features may not be available for all languages
- Try
--semantic-off
for basic analysis
Pattern Errors
Message: Pattern error: invalid glob pattern
Meaning: Invalid glob pattern in configuration or CLI
Solutions:
- Check glob pattern syntax
- Escape special characters if needed
- Test pattern with shell glob:
ls <pattern>
- Use simpler patterns or path prefixes
Language-Specific Issues
Rust
Macro Expansion Issues
# See macro warnings
debtmap --verbose-macro-warnings
# Show macro statistics
debtmap --show-macro-stats
# Common issue: Complex macros may not expand correctly
# Solution: Use --semantic-off for faster fallback
Trait and Generic Complexity
Complex trait bounds and generic constraints may affect analysis accuracy:
# Full semantic analysis (default)
debtmap
# Fallback mode for edge cases
debtmap --semantic-off
Python
Type Inference Limitations
Dynamic typing makes some analysis challenging:
# Best effort type inference (default)
debtmap
# Fallback mode if issues
debtmap --semantic-off
Import Resolution
Complex import structures may not resolve fully:
- Relative imports usually work
- Dynamic imports may not be detected
__init__.py
packages are supported
JavaScript/TypeScript
JSX/TSX Parsing
Ensure files have correct extensions:
.jsx
for JavaScript + JSX.tsx
for TypeScript + JSX- Configure extensions in
.debtmap/config.toml
if needed
Type Resolution
TypeScript type resolution in complex projects:
# Full type checking (default for .ts files)
debtmap
# Fallback if type issues
debtmap --semantic-off
Mixed Language Projects
# Analyze all supported languages (default)
debtmap
# Filter specific languages
# In .debtmap/config.toml:
# languages = ["rust", "python"]
Unsupported Language Constructs
Some advanced language features may show as “Unsupported”:
- Rust: Some macro patterns, const generics edge cases
- Python: Some metaclass patterns, dynamic code generation
- JavaScript: Some advanced AST manipulation
Solutions:
- Use
--semantic-off
for basic analysis - Exclude problematic files if needed
- Report unsupported patterns as feature requests
False Positives
# Reduce false positives with context
debtmap --context
# Adjust thresholds
debtmap --threshold-preset lenient
# Disable context-aware filtering if too aggressive
debtmap --no-context-aware
Missing Detections
# Ensure semantic analysis is enabled
debtmap # (default, semantic ON)
# Increase verbosity to see what's detected
debtmap -vv
# Check if files are being analyzed
debtmap -v 2>&1 | grep "Processing"
Output Formatting Issues
Choose Output Format
# Terminal format (default, human-readable)
debtmap
# JSON format
debtmap --format json
# Markdown format
debtmap --format markdown
JSON Format Options
# Legacy format (default): {File: {...}}
debtmap --format json --output-format legacy
# Unified format: consistent structure with 'type' field
debtmap --format json --output-format unified
# Validate JSON
debtmap --format json | jq .
# Write to file
debtmap --format json --output results.json
Plain Output Mode
For environments without color/emoji support:
# ASCII-only, no colors, no emoji
debtmap --plain
# Or set environment variable
export NO_EMOJI=1
debtmap
Terminal Color Issues
Problem: Colors not rendering or showing escape codes
Solutions:
# Use plain mode
debtmap --plain
# Check TERM environment variable
echo $TERM
# Set appropriate TERM
export TERM=xterm-256color
Emoji Issues
Problem: Emojis showing as boxes or ??
Solutions:
# Disable emojis
debtmap --plain
# Or environment variable
export NO_EMOJI=1
debtmap
Markdown Rendering
Ensure viewer supports GitHub-flavored markdown:
- Tables
- Code blocks with syntax highlighting
- Task lists
Write Output to File
# JSON to file
debtmap --format json --output results.json
# Markdown to file
debtmap --format markdown --output report.md
# Terminal format to file (preserves colors)
debtmap --output results.txt
# Plain format to file
debtmap --plain --output results.txt
Summary vs Full Output
# Summary mode (compact)
debtmap --summary
debtmap -s
# Full output (default)
debtmap
# Limit number of items
debtmap --top 10 # Top 10 by priority
debtmap --tail 10 # Bottom 10 by priority
Filtering Output
# Minimum priority level
debtmap --min-priority 5
# Category filters
debtmap --filter "complexity,debt"
# Combine filters
debtmap --min-priority 3 --top 20 --filter complexity
Compare Command Issues
The compare
command helps track changes in technical debt over time.
Basic Usage
Note: The compare
command defaults to JSON output format (unlike analyze
which defaults to terminal). Use --format terminal
or --format markdown
if you need different output.
# Save baseline results
debtmap --format json --output before.json
# Make code changes...
# Save new results
debtmap --format json --output after.json
# Compare results (outputs JSON by default)
debtmap compare --before before.json --after after.json
# Compare with terminal output
debtmap compare --before before.json --after after.json --format terminal
Targeted Comparison
Use --plan
and --target-location
for focused debt analysis:
# Compare based on implementation plan
debtmap compare --before before.json --after after.json --plan implementation-plan.json
# Compare specific code location
debtmap compare --before before.json --after after.json \
--target-location src/main.rs:calculate_score:42
# Combine both for precise tracking
debtmap compare --before before.json --after after.json \
--plan implementation-plan.json \
--target-location src/analyzers/complexity.rs:analyze_function:128
Use cases:
--plan
: Track debt changes for planned refactoring tasks--target-location
: Focus on specific function or code location- Combine for granular technical debt tracking
Incompatible Format Errors
Problem: “Incompatible formats” error when comparing files
Causes:
- Mixing legacy and unified JSON formats
- Files from different debtmap versions
- Corrupted JSON files
Solutions:
# Ensure both files use same output format
debtmap --format json --output-format unified --output before.json
# ... make changes ...
debtmap --format json --output-format unified --output after.json
debtmap compare --before before.json --after after.json
# Validate JSON files are well-formed
jq . before.json > /dev/null
jq . after.json > /dev/null
Comparing Across Branches
# Save baseline on main branch
git checkout main
debtmap --format json --output main.json
# Switch to feature branch
git checkout feature-branch
debtmap --format json --output feature.json
# Compare branches
debtmap compare --before main.json --after feature.json
Missing Files Error
Problem: “File not found” when running compare
Solutions:
- Verify file paths are correct (use absolute paths if needed)
- Ensure JSON files weren’t moved or deleted
- Check current working directory with
pwd
Format Mismatch Issues
Problem: Compare shows unexpected differences or errors
Solutions:
# Regenerate both files with same debtmap version
debtmap --format json --output before.json
# ... make changes ...
debtmap --format json --output after.json
# Use same output format for both
debtmap --format json --output-format unified --output before.json
debtmap --format json --output-format unified --output after.json
Validate Command Issues
The validate
command checks if a codebase meets specified quality thresholds, useful for CI/CD pipelines.
Basic Validation
# Validate codebase passes default thresholds
debtmap validate /path/to/project
# Exit code 0 if passes, non-zero if validation fails
Debt Density Validation
Flag: --max-debt-density <number>
Sets the maximum acceptable technical debt per 1000 lines of code.
# Set maximum acceptable debt density (per 1000 LOC)
debtmap validate /path/to/project --max-debt-density 10.0
# Stricter threshold for critical projects
debtmap validate /path/to/project --max-debt-density 5.0
# Lenient threshold for legacy code
debtmap validate /path/to/project --max-debt-density 20.0
Troubleshooting validation failures:
# See which files exceed threshold
debtmap validate /path/to/project --max-debt-density 10.0 -v
# Get detailed breakdown
debtmap validate /path/to/project --max-debt-density 10.0 -vv
# Analyze specific files that failed
debtmap /path/to/problematic/file.rs -v
CI/CD Integration
# In CI pipeline (fails build if validation fails)
debtmap validate . --max-debt-density 10.0 || exit 1
# With verbose output for debugging
debtmap validate . --max-debt-density 10.0 -v
# Save validation report
debtmap validate . --max-debt-density 10.0 --format json --output validation.json
Use cases:
- Enforce quality gates in CI/CD pipelines
- Prevent accumulation of technical debt over time
- Track debt density trends across releases
- Set different thresholds for different parts of codebase
FAQ
General Questions
Q: Why is my analysis slow?
A: Check several factors:
# Check cache status
debtmap --cache-stats
# Ensure caching is enabled (default)
# Remove --no-cache if present
# Use all CPU cores
debtmap --jobs 0
# Check for large files or complex macros
debtmap -vv
Q: What does ‘Parse error’ mean?
A: File contains syntax debtmap cannot parse. Solutions:
- Try
--semantic-off
for fallback mode - Use
--verbose-macro-warnings
for Rust macros - Exclude problematic files in
.debtmap/config.toml
- Report parse errors as potential bugs
Q: Why do scores differ between runs?
A: Several factors affect scores:
- Coverage file changed (use
--coverage-file
) - Context providers enabled/disabled (
--context
) - Cache was cleared (
--clear-cache
) - Code changes (intended behavior)
- Different threshold settings
Q: How do I reduce noise in results?
A: Use filtering options:
# Increase minimum priority
debtmap --min-priority 5
# Use threshold preset
debtmap --threshold-preset strict
# Filter categories
debtmap --filter "complexity,debt"
# Limit output
debtmap --top 20
Format and Output
Q: What’s the difference between legacy and unified JSON?
A: Two JSON output formats:
- Legacy:
{File: {...}}
- nested file-based structure - Unified: Consistent structure with
type
field for each item
# Legacy (default)
debtmap --format json --output-format legacy
# Unified (recommended for parsing)
debtmap --format json --output-format unified
Q: Can I analyze partial codebases?
A: Yes, several approaches:
# Limit file count
debtmap --max-files 100
# Analyze specific directory
debtmap src/specific/module
# Use filters in config
# .debtmap/config.toml:
# include = ["src/**/*.rs"]
Coverage and Testing
Q: How does coverage affect scores?
A: Coverage dampens scores to surface untested code:
- Formula:
score_multiplier = 1.0 - coverage
- 0% coverage → full score (highest priority)
- 100% coverage → score multiplied by 0 (lowest priority)
- Untested complex code rises to the top
# Use coverage file
debtmap --coverage-file coverage.info
# See coverage impact
debtmap --coverage-file coverage.info -v
Context and Analysis
Q: What are context providers?
A: Additional analysis for prioritization:
- critical_path: Call graph analysis, entry point distance
- dependency: Dependency relationships and coupling
- git_history: Change frequency and authorship
# Enable all
debtmap --context
# Specific providers
debtmap --context --context-providers critical_path,dependency
# See context impact
debtmap --context -v
Results and Comparison
Q: Why no output?
A: Check verbosity and filtering:
# Increase verbosity
debtmap -v
# Lower priority threshold
debtmap --min-priority 0
# Check if files were analyzed
debtmap -vv 2>&1 | grep "Processed"
# Ensure not using strict threshold
debtmap --threshold-preset lenient
Q: How to compare results over time?
A: Use the compare
command:
# Save baseline
debtmap --format json --output before.json
# Make changes...
# Analyze again
debtmap --format json --output after.json
# Compare
debtmap compare --before before.json --after after.json
Q: Why does compare fail with ‘incompatible formats’?
A: The JSON files must use the same output format:
# Use unified format for both
debtmap --format json --output-format unified --output before.json
# ... make changes ...
debtmap --format json --output-format unified --output after.json
debtmap compare --before before.json --after after.json
# Or use legacy format for both (but unified is recommended)
debtmap --format json --output-format legacy --output before.json
debtmap --format json --output-format legacy --output after.json
Q: How do I compare results from different branches?
A: Generate JSON output on each branch and compare:
# On main branch
git checkout main
debtmap --format json --output main.json
# On feature branch
git checkout feature-branch
debtmap --format json --output feature.json
# Compare (from either branch)
debtmap compare --before main.json --after feature.json
Q: Can I compare legacy and unified JSON formats?
A: No, both files must use the same format. Regenerate with matching formats:
# Convert both to unified format
debtmap --format json --output-format unified --output before.json
debtmap --format json --output-format unified --output after.json
debtmap compare --before before.json --after after.json
Performance and Optimization
Q: How many threads should I use?
A: Depends on your machine:
# Use all cores (default, recommended)
debtmap --jobs 0
# Limit to 4 threads (if other work running)
debtmap --jobs 4
# Single threaded (debugging only)
debtmap --no-parallel
Q: Should I use shared or local cache?
A: Depends on your workflow:
- Local cache (
.debtmap/cache
): Isolated, automatic - Shared cache (
~/.cache/debtmap
): Saves space across projects
# Shared cache
debtmap --cache-location ~/.cache/debtmap
# Set permanently
export DEBTMAP_CACHE_DIR=~/.cache/debtmap
When to File Bug Reports
File a bug report when:
✅ These are bugs:
- Parse errors on valid syntax
- Crashes or panics
- Incorrect complexity calculations
- Cache corruption
- Concurrency errors
- Incorrect error messages
❌ These are not bugs:
- Unsupported language constructs (file feature request)
- Disagreement with complexity scores (subjective)
- Performance on very large codebases (optimization request)
- Missing documentation (docs issue, not code bug)
How to Report Issues
- Reproduce with minimal example
- Include debug output:
debtmap -vvv 2>&1 | tee error.log
- Include version:
debtmap --version
- Include platform: OS, Rust version if relevant
- Include configuration:
.debtmap/config.toml
if used - Expected vs actual behavior
Before Filing
- Check this troubleshooting guide
- Try
--semantic-off
fallback mode - Clear cache with
--clear-cache
- Update to latest version
- Search existing issues on GitHub
Related Documentation
- Configuration Guide: Configure debtmap behavior
- CLI Reference: Complete CLI flag documentation
- Analysis Guide: Understanding analysis results
- Examples: Practical usage examples
- API Documentation: Rust API documentation
Troubleshooting Checklist
When debugging issues, work through this checklist:
-
Run with
-vv
to see detailed output -
Check
--cache-stats
for cache issues -
Try
--clear-cache
to rule out cache corruption -
Try
--semantic-off
to use fallback mode - Check file permissions and paths
-
Verify configuration in
.debtmap/config.toml
-
Test with
--max-files 10
to isolate issues -
Try
--no-parallel
to rule out concurrency -
Check
debtmap --version
for updates - Review error messages in this guide
- Search GitHub issues for similar problems
- Create minimal reproduction case
- File bug report with debug output