/estimate-assistant
Generate accurate project time estimates
$ npx -y skills add qdhenry/Claude-Command-Suite --agent claude-codeHow it fires
How this command gets triggered: by you, by Claude, or both.
- Fires itselfClaude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/estimate-assistant
Context preview
What this command does when you run it.
Generate accurate project time estimates
Command definition
estimate-assistant.mdestimate-assistant
Generate accurate project time estimates
Purpose
This command analyzes past commits, PR completion times, code complexity metrics, and team performance to provide accurate task estimates. It helps teams move beyond gut-feel estimates to data-backed predictions.
Usage
# Estimate a specific task based on description
claude "Estimate task: Implement OAuth2 login flow with Google"
# Analyze historical accuracy of estimates
claude "Show estimation accuracy for the last 10 sprints"
# Estimate based on code changes
claude "Estimate effort for refactoring src/api/users module"
# Get team member specific estimates
claude "How long would it take Alice to implement the payment webhook handler?"
Instructions
1. Gather Historical Data
Collect data from git history and Linear:
# Get commit history with timestamps and authors
git log --pretty=format:"%h|%an|%ad|%s" --date=iso --since="6 months ago" > commit_history.txt
# Analyze PR completion times
gh pr list --state closed --limit 100 --json number,title,createdAt,closedAt,additions,deletions,files
# Get file change frequency
git log --pretty=format: --name-only --since="6 months ago" | sort | uniq -c | sort -rn
# Analyze commit patterns by author
git shortlog -sn --since="6 months ago"
2. Calculate Code Complexity Metrics
Analyze code characteristics:
function analyzeComplexity(filePath) {
const metrics = {
lines: 0,
cyclomaticComplexity: 0,
dependencies: 0,
testCoverage: 0,
similarFiles: []
};
// Count lines of code
const content = readFile(filePath);
metrics.lines = content.split('\n').length;
// Cyclomatic complexity (simplified)
const conditions = content.match(/if\s*\(|while\s*\(|for\s*\(|case\s+|\?\s*:/g);
metrics.cyclomaticComplexity = (conditions?.length || 0) + 1;
// Count imports/dependencies
const imports = content.match(/import.*from|require\(/g);
metrics.dependencies = imports?.length || 0;
// Find similar files by structure
metrics.similarFiles = findSimilarFiles(filePath);
return metrics;
}3. Build Estimation Models
Time-Based Estimation
class HistoricalEstimator {
constructor(gitData, linearData) {
this.gitData = gitData;
this.linearData = linearData;
this.authorVelocity = new Map();
this.fileTypeMultipliers = new Map();
}
calculateAuthorVelocity(author) {
const authorCommits = this.gitData.filter(c => c.author === author);
const taskCompletions = this.linearData.filter(t =>
t.assignee === author && t.completedAt
);
// Lines of code per day
const totalLines = authorCommits.reduce((sum, c) =>
sum + c.additions + c.deletions, 0
);
const totalDays = this.calculateWorkDays(authorCommits);
const linesPerDay = totalLines / totalDays;
// Story points per sprint
const pointsCompleted = taskCompletions.reduce((sum, t) =>
sum + (t.estimate || 0), 0
);
const sprintCount = this.countSprints(taskCompletions);
const pointsPerSprint = pointsCompleted / sprintCount;
return {
linesPerDay,
pointsPerSprint,
averageTaskDuration: this.calculateAverageTaskDuration(taskCompletions),
accuracy: this.calculateEstimateAccuracy(taskCompletions)
};
}
estimateTask(description, assignee = null) {
// Extract key features from description
const features = this.extractFeatures(description);
// Find similar completed tasks
const similarTasks = this.findSimilarTasks(features);
// Base estimate from similar tasks
let baseEstimate = this.calculateMedianEstimate(similarTasks);
// Adjust for complexity indicators
const complexityMultiplier = this.calculateComplexityMultiplier(features);
baseEstimate *= complexityMultiplier;
// Adjust for assignee if specified
if (assignee) {
const velocity = this.calculateAuthorVelocity(assignee);
const teamAvgVelocity = this.calculateTeamAverageVelocity();
const velocityRatio = velocity.pointsPerSprint / teamAvgVelocity;
baseEstimate *= (2 - velocityRatio); // Faster devs get lower estimates
}
// Add confidence interval
const confidence = this.calculateConfidence(similarTasks.length, features);
return {
estimate: Math.round(baseEstimate),
confidence,
range: {
min: Math.round(baseEstimate * 0.7),
max: Math.round(baseEstimate * 1.5)
},
basedOn: similarTasks.slice(0, 3),
factors: this.explainFactors(features, complexityMultiplier)
};
}
}Pattern Recognition
function extractFeatures(taskDescription) {
const features = {
keywords: [],
fileTypes: [],
modules: [],
complexity: 'medium',
type: 'feature', // feature, bug, refactor, etc.
hasTests: false,
hasUI: false,
hasAPI: false,
hasDatabase: false
};
// Keywords that indicate complexity
const complexityKeywords = {
high: ['refactor', 'migrate', 'redesign', 'optimize', 'architecture'],
medium: ['implement', 'add', 'create', 'update', 'integrate'],
low: ['fix', 'adjust', 'tweak', 'change', 'modify']
};
// Detect task type
if (taskDescription.match(/bug|fix|repair|broken/i)) {
features.type = 'bug';
} else if (taskDescription.match(/refactor|cleanup|optimize/i)) {
features.type = 'refactor';
} else if (taskDescription.match(/test|spec|coverage/i)) {
features.type = 'test';
}
// Detect components
features.hasUI = /UI|frontend|component|view|page/i.test(taskDescription);
features.hasAPI = /API|endpoint|route|REST|GraphQL/i.test(taskDescription);
features.hasDatabase = /database|DB|migration|schema|query/i.test(taskDescription);
features.hasTests = /test|spec|TDD|coverage/i.test(taskDescription);
// Extract file types mentioned
const fileTypeMatches = taskDescription.match(/\.(Read more
estimate-assistant
Generate accurate project time estimates
Purpose
This command analyzes past commits, PR completion times, code complexity metrics, and team performance to provide accurate task estimates. It helps teams move beyond gut-feel estimates to data-backed predictions.
Usage
# Estimate a specific task based on description claude "Estimate task: Implement OAuth2 login flow with Google" # Analyze historical accuracy of estimates claude "Show estimation accuracy for the last 10 sprints" # Estimate based on code changes claude "Estimate effort for refactoring src/api/users module" # Get team member specific estimates claude "How long would it take Alice to implement the payment webhook handler?"
Instructions
1. Gather Historical Data
Collect data from git history and Linear:
# Get commit history with timestamps and authors git log --pretty=format:"%h|%an|%ad|%s" --date=iso --since="6 months ago" > commit_history.txt # Analyze PR completion times gh pr list --state closed --limit 100 --json number,title,createdAt,closedAt,additions,deletions,files # Get file change frequency git log --pretty=format: --name-only --since="6 months ago" | sort | uniq -c | sort -rn # Analyze commit patterns by author git shortlog -sn --since="6 months ago"
2. Calculate Code Complexity Metrics
Analyze code characteristics:
function analyzeComplexity(filePath) {
const metrics = {
lines: 0,
cyclomaticComplexity: 0,
dependencies: 0,
testCoverage: 0,
similarFiles: []
};
// Count lines of code
const content = readFile(filePath);
metrics.lines = content.split('\n').length;
// Cyclomatic complexity (simplified)
const conditions = content.match(/if\s*\(|while\s*\(|for\s*\(|case\s+|\?\s*:/g);
metrics.cyclomaticComplexity = (conditions?.length || 0) + 1;
// Count imports/dependencies
const imports = content.match(/import.*from|require\(/g);
metrics.dependencies = imports?.length || 0;
// Find similar files by structure
metrics.similarFiles = findSimilarFiles(filePath);
return metrics;
}3. Build Estimation Models
Time-Based Estimation
class HistoricalEstimator {
constructor(gitData, linearData) {
this.gitData = gitData;
this.linearData = linearData;
this.authorVelocity = new Map();
this.fileTypeMultipliers = new Map();
}
calculateAuthorVelocity(author) {
const authorCommits = this.gitData.filter(c => c.author === author);
const taskCompletions = this.linearData.filter(t =>
t.assignee === author && t.completedAt
);
// Lines of code per day
const totalLines = authorCommits.reduce((sum, c) =>
sum + c.additions + c.deletions, 0
);
const totalDays = this.calculateWorkDays(authorCommits);
const linesPerDay = totalLines / totalDays;
// Story points per sprint
const pointsCompleted = taskCompletions.reduce((sum, t) =>
sum + (t.estimate || 0), 0
);
const sprintCount = this.countSprints(taskCompletions);
const pointsPerSprint = pointsCompleted / sprintCount;
return {
linesPerDay,
pointsPerSprint,
averageTaskDuration: this.calculateAverageTaskDuration(taskCompletions),
accuracy: this.calculateEstimateAccuracy(taskCompletions)
};
}
estimateTask(description, assignee = null) {
// Extract key features from description
const features = this.extractFeatures(description);
// Find similar completed tasks
const similarTasks = this.findSimilarTasks(features);
// Base estimate from similar tasks
let baseEstimate = this.calculateMedianEstimate(similarTasks);
// Adjust for complexity indicators
const complexityMultiplier = this.calculateComplexityMultiplier(features);
baseEstimate *= complexityMultiplier;
// Adjust for assignee if specified
if (assignee) {
const velocity = this.calculateAuthorVelocity(assignee);
const teamAvgVelocity = this.calculateTeamAverageVelocity();
const velocityRatio = velocity.pointsPerSprint / teamAvgVelocity;
baseEstimate *= (2 - velocityRatio); // Faster devs get lower estimates
}
// Add confidence interval
const confidence = this.calculateConfidence(similarTasks.length, features);
return {
estimate: Math.round(baseEstimate),
confidence,
range: {
min: Math.round(baseEstimate * 0.7),
max: Math.round(baseEstimate * 1.5)
},
basedOn: similarTasks.slice(0, 3),
factors: this.explainFactors(features, complexityMultiplier)
};
}
}Pattern Recognition
function extractFeatures(taskDescription) {
const features = {
keywords: [],
fileTypes: [],
modules: [],
complexity: 'medium',
type: 'feature', // feature, bug, refactor, etc.
hasTests: false,
hasUI: false,
hasAPI: false,
hasDatabase: false
};
// Keywords that indicate complexity
const complexityKeywords = {
high: ['refactor', 'migrate', 'redesign', 'optimize', 'architecture'],
medium: ['implement', 'add', 'create', 'update', 'integrate'],
low: ['fix', 'adjust', 'tweak', 'change', 'modify']
};
// Detect task type
if (taskDescription.match(/bug|fix|repair|broken/i)) {
features.type = 'bug';
} else if (taskDescription.match(/refactor|cleanup|optimize/i)) {
features.type = 'refactor';
} else if (taskDescription.match(/test|spec|coverage/i)) {
features.type = 'test';
}
// Detect components
features.hasUI = /UI|frontend|component|view|page/i.test(taskDescription);
features.hasAPI = /API|endpoint|route|REST|GraphQL/i.test(taskDescription);
features.hasDatabase = /database|DB|migration|schema|query/i.test(taskDescription);
features.hasTests = /test|spec|TDD|coverage/i.test(taskDescription);
// Extract file types mentioned
const fileTypeMatches = taskDescription.match(/\.(A comprehensive development toolkit designed following Anthropic's Claude Code Best Practices for AI-assisted software development.
Repo: qdhenry/Claude-Command-Suite
Other commands on claude-command-suite.
- /boundary-bbcr-fallback
Execute automatic BBCR (Collapse-Rebirth Correction) when knowledge boundaries are exceeded or reasoning fails.
Open command - /boundary-detect
Analyze semantic position relative to knowledge boundaries to prevent hallucination and identify uncertainty zones.
Open command - /boundary-heatmap
Generate a visual heatmap of knowledge boundaries showing safe zones, risk areas, and semantic coverage.
Open command - /boundary-risk-assess
Evaluate the current risk level and provide detailed analysis of potential hallucination or reasoning failure.
Open command - /boundary-safe-bridge
Find and construct semantic bridges to safely navigate from current position to target concept without crossing dangerous boundaries.
Open command - /optimize-prompt
Takes an input prompt and returns ONLY a token-optimized version that preserves meaning while minimizing token count. Based on LLM tokenization principles: common words tokenize more efficiently, unusual words break into more tokens, and conciseness reduces cost.
Open command

