
Technical Debt Assessment
- 460 installs
- 305 repo stars
- Updated March 4, 2026
- aj-geddes/useful-ai-prompts
technical-debt-assessment is a Claude Code skill that inventories legacy hotspots, scores maintenance risk, and ranks refactors using code analysis, metrics, and impact modeling.
About
technical-debt-assessment is a Claude Code skill in aj-geddes/useful-ai-prompts that systematically identifies, measures, and prioritizes technical debt across code, architecture, tests, documentation, security, and performance categories. The workflow scans repositories for anti-patterns such as duplicated code, long methods, missing tests, outdated dependencies, and architectural coupling, then estimates remediation effort, debt hours, and ongoing interest cost if left unfixed. A priority formula weights severity, impact, interest, and effort to produce ranked remediation lists, category breakdowns, and sprint-ready summaries for refactoring, backlog grooming, acquisition due diligence, or quality gate planning. Developers reach for technical-debt-assessment when releases slow, defect rates climb, or on-call burden rises because legacy shortcuts compound. The skill includes a TechnicalDebtAssessment registry pattern for adding debt items with severity, effort, impact, and interest fields, supporting ROI-focused conversations with engineering leadership.
- Structured debt inventory prompts
- Risk and blast-radius scoring
- Refactor prioritization frameworks
- Stakeholder-ready remediation summaries
- Regression-risk triage guidance
Technical Debt Assessment by the numbers
- 460 all-time installs (skills.sh)
- Ranked #246 of 1,352 Code Review & Quality skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/aj-geddes/useful-ai-prompts --skill technical-debt-assessmentAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 460 |
|---|---|
| repo stars | ★ 305 |
| Last updated | March 4, 2026 |
| Repository | aj-geddes/useful-ai-prompts ↗ |
How do you prioritize technical debt in a codebase?
Inventory legacy hotspots, score maintenance risk, and rank refactors so teams fix the debt most likely to slow releases, raise defect rates, or inflate on-call burden.
Who is it for?
Tech leads and senior developers planning refactors, sprint debt budgets, or due diligence on legacy repositories with measurable risk scoring.
Skip if: Greenfield projects with little legacy code or teams seeking feature design prompts instead of codebase quality analysis.
When should I use this skill?
User asks to assess technical debt, prioritize refactors, score legacy risk, or plan sprint debt remediation with effort and impact metrics.
What you get
Prioritized debt register with severity scores, remediation effort hours, interest costs, category breakdowns, and top refactor recommendations.
- Prioritized debt register
- Category breakdown report
- Sprint remediation recommendations
By the numbers
- Covers 6 technical debt categories in assessment output
- Uses severity, effort, impact, and interest fields per debt registry item
Files
Technical Debt Assessment
Table of Contents
Overview
Systematically identify, measure, and manage technical debt to make informed decisions about code quality investments.
When to Use
- Legacy code evaluation
- Refactoring prioritization
- Sprint planning
- Code quality initiatives
- Acquisition due diligence
- Architectural decisions
Quick Start
Minimal working example:
interface DebtItem {
id: string;
title: string;
description: string;
category: "code" | "architecture" | "test" | "documentation" | "security";
severity: "low" | "medium" | "high" | "critical";
effort: number; // hours
impact: number; // 1-10 scale
interest: number; // cost per sprint if not fixed
}
class TechnicalDebtAssessment {
private items: DebtItem[] = [];
addDebtItem(item: DebtItem): void {
this.items.push(item);
}
calculatePriority(item: DebtItem): number {
const severityWeight = {
low: 1,
medium: 2,
high: 3,
critical: 4,
};
// ... (see reference guides for full implementation)Reference Guides
Detailed implementations in the references/ directory:
| Guide | Contents |
|---|---|
| Technical Debt Calculator | Technical Debt Calculator |
| Code Quality Scanner | Code Quality Scanner |
Best Practices
✅ DO
- Quantify debt impact
- Prioritize by ROI
- Track debt over time
- Include debt in sprints
- Document debt decisions
- Set quality gates
❌ DON'T
- Ignore technical debt
- Fix everything at once
- Skip impact analysis
- Make emotional decisions
Code Quality Scanner
Code Quality Scanner
import * as ts from "typescript";
import * as fs from "fs";
interface QualityIssue {
file: string;
line: number;
issue: string;
severity: "info" | "warning" | "error";
debtHours: number;
}
class CodeQualityScanner {
private issues: QualityIssue[] = [];
scanProject(directory: string): QualityIssue[] {
this.issues = [];
const files = this.getTypeScriptFiles(directory);
for (const file of files) {
this.scanFile(file);
}
return this.issues;
}
private scanFile(filePath: string): void {
const sourceCode = fs.readFileSync(filePath, "utf-8");
const sourceFile = ts.createSourceFile(
filePath,
sourceCode,
ts.ScriptTarget.Latest,
true,
);
// Check for anti-patterns
this.checkForAnyTypes(sourceFile, filePath);
this.checkForLongFunctions(sourceFile, filePath);
this.checkForMagicNumbers(sourceFile, filePath);
this.checkForConsoleStatements(sourceFile, filePath);
this.checkForTodoComments(sourceFile, filePath);
}
private checkForAnyTypes(sourceFile: ts.SourceFile, filePath: string): void {
const visit = (node: ts.Node) => {
if (ts.isTypeReferenceNode(node) && node.typeName.getText() === "any") {
const { line } = ts.getLineAndCharacterOfPosition(
sourceFile,
node.getStart(),
);
this.issues.push({
file: filePath,
line: line + 1,
issue: "Use of any type reduces type safety",
severity: "warning",
debtHours: 0.5,
});
}
ts.forEachChild(node, visit);
};
visit(sourceFile);
}
private checkForLongFunctions(
sourceFile: ts.SourceFile,
filePath: string,
): void {
const visit = (node: ts.Node) => {
if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {
if (node.body) {
const lines = node.body.getFullText().split("\n").length;
if (lines > 50) {
const { line } = ts.getLineAndCharacterOfPosition(
sourceFile,
node.getStart(),
);
this.issues.push({
file: filePath,
line: line + 1,
issue: `Function has ${lines} lines, should be refactored`,
severity: "warning",
debtHours: Math.ceil(lines / 10),
});
}
}
}
ts.forEachChild(node, visit);
};
visit(sourceFile);
}
private checkForMagicNumbers(
sourceFile: ts.SourceFile,
filePath: string,
): void {
const visit = (node: ts.Node) => {
if (ts.isNumericLiteral(node)) {
const value = parseFloat(node.text);
// Ignore common constants
if (![0, 1, -1, 2].includes(value)) {
const { line } = ts.getLineAndCharacterOfPosition(
sourceFile,
node.getStart(),
);
this.issues.push({
file: filePath,
line: line + 1,
issue: `Magic number ${value} should be a named constant`,
severity: "info",
debtHours: 0.1,
});
}
}
ts.forEachChild(node, visit);
};
visit(sourceFile);
}
private checkForConsoleStatements(
sourceFile: ts.SourceFile,
filePath: string,
): void {
const text = sourceFile.getFullText();
const lines = text.split("\n");
lines.forEach((line, index) => {
if (line.includes("console.log") || line.includes("console.error")) {
this.issues.push({
file: filePath,
line: index + 1,
issue: "Console statement should use proper logger",
severity: "info",
debtHours: 0.1,
});
}
});
}
private checkForTodoComments(
sourceFile: ts.SourceFile,
filePath: string,
): void {
const text = sourceFile.getFullText();
const lines = text.split("\n");
lines.forEach((line, index) => {
if (/\/\/\s*TODO/.test(line)) {
this.issues.push({
file: filePath,
line: index + 1,
issue: "TODO comment indicates incomplete work",
severity: "warning",
debtHours: 2,
});
}
});
}
private getTypeScriptFiles(dir: string): string[] {
// Implementation
return [];
}
getTotalDebt(): number {
return this.issues.reduce((sum, issue) => sum + issue.debtHours, 0);
}
generateReport(): string {
let report = "# Code Quality Report\n\n";
const bySeverity = this.issues.reduce(
(acc, issue) => {
acc[issue.severity] = acc[issue.severity] || [];
acc[issue.severity].push(issue);
return acc;
},
{} as Record<string, QualityIssue[]>,
);
report += `## Summary\n\n`;
report += `- Total Issues: ${this.issues.length}\n`;
report += `- Estimated Debt: ${this.getTotalDebt()} hours\n\n`;
for (const [severity, issues] of Object.entries(bySeverity)) {
report += `### ${severity.toUpperCase()} (${issues.length})\n\n`;
for (const issue of issues.slice(0, 10)) {
report += `- ${issue.file}:${issue.line} - ${issue.issue}\n`;
}
report += "\n";
}
return report;
}
}Technical Debt Calculator
Technical Debt Calculator
interface DebtItem {
id: string;
title: string;
description: string;
category: "code" | "architecture" | "test" | "documentation" | "security";
severity: "low" | "medium" | "high" | "critical";
effort: number; // hours
impact: number; // 1-10 scale
interest: number; // cost per sprint if not fixed
}
class TechnicalDebtAssessment {
private items: DebtItem[] = [];
addDebtItem(item: DebtItem): void {
this.items.push(item);
}
calculatePriority(item: DebtItem): number {
const severityWeight = {
low: 1,
medium: 2,
high: 3,
critical: 4,
};
const priority =
(item.impact * 10 +
item.interest * 5 +
severityWeight[item.severity] * 3) /
(item.effort + 1);
return priority;
}
getPrioritizedList(): Array<DebtItem & { priority: number }> {
return this.items
.map((item) => ({
...item,
priority: this.calculatePriority(item),
}))
.sort((a, b) => b.priority - a.priority);
}
getDebtByCategory(): Record<string, DebtItem[]> {
return this.items.reduce(
(acc, item) => {
acc[item.category] = acc[item.category] || [];
acc[item.category].push(item);
return acc;
},
{} as Record<string, DebtItem[]>,
);
}
getTotalEffort(): number {
return this.items.reduce((sum, item) => sum + item.effort, 0);
}
getTotalInterest(): number {
return this.items.reduce((sum, item) => sum + item.interest, 0);
}
generateReport(): string {
const prioritized = this.getPrioritizedList();
const byCategory = this.getDebtByCategory();
let report = "# Technical Debt Assessment\n\n";
// Summary
report += "## Summary\n\n";
report += `- Total Items: ${this.items.length}\n`;
report += `- Total Effort: ${this.getTotalEffort()} hours\n`;
report += `- Monthly Interest: ${this.getTotalInterest()} hours\n\n`;
// By Category
report += "## By Category\n\n";
for (const [category, items] of Object.entries(byCategory)) {
const effort = items.reduce((sum, item) => sum + item.effort, 0);
report += `- ${category}: ${items.length} items (${effort} hours)\n`;
}
report += "\n";
// Top Priority Items
report += "## Top Priority Items\n\n";
for (const item of prioritized.slice(0, 10)) {
report += `### ${item.title} (Priority: ${item.priority.toFixed(2)})\n`;
report += `- Category: ${item.category}\n`;
report += `- Severity: ${item.severity}\n`;
report += `- Effort: ${item.effort} hours\n`;
report += `- Impact: ${item.impact}/10\n`;
report += `- Interest: ${item.interest} hours/sprint\n`;
report += `\n${item.description}\n\n`;
}
return report;
}
}
// Usage
const assessment = new TechnicalDebtAssessment();
assessment.addDebtItem({
id: "debt-1",
title: "Legacy API endpoints",
description: "Old API v1 endpoints still in use, need migration",
category: "architecture",
severity: "high",
effort: 40,
impact: 8,
interest: 5,
});
assessment.addDebtItem({
id: "debt-2",
title: "Missing unit tests",
description: "30% of codebase lacks test coverage",
category: "test",
severity: "medium",
effort: 80,
impact: 7,
interest: 3,
});
console.log(assessment.generateReport());Process: [Name]
Purpose
TODO: Why this process exists.
Roles & Responsibilities
| Role | Responsibility |
|---|---|
| TODO | TODO |
Steps
1. TODO: First step 2. TODO: Second step 3. TODO: Third step
Inputs & Outputs
- Input: TODO
- Output: TODO
Success Criteria
- TODO: Define measurable success criteria
Review Cadence
TODO: How often to review this process.
Related skills
How it compares
Pick technical-debt-assessment over generic code review skills when you need quantified debt scoring, interest modeling, and prioritized refactor lists across multiple quality dimensions.
FAQ
What categories does technical-debt-assessment cover?
technical-debt-assessment covers six debt categories—code, architecture, test, documentation, security, and performance—scanning each for anti-patterns, estimated remediation effort, and ongoing interest if unresolved.
How does technical-debt-assessment rank debt items?
technical-debt-assessment ranks debt items with a priority formula that weights severity, business impact, ongoing interest cost, and estimated remediation effort, producing ordered lists for refactoring and sprint planning.
When should teams run technical-debt-assessment?
Teams should run technical-debt-assessment before major releases or migrations, during backlog grooming, for acquisition due diligence, or when defect rates and on-call load suggest legacy debt is slowing delivery.