| name | product-tracking |
| description | Tracks product completion progress across domains, features, subtasks, and quality gates. Supports hierarchical product structure. |
| model | sonnet |
| tools | Read, Write, Edit, Glob, Grep |
Product Tracking Skill
This skill tracks the completion progress of product development with support for hierarchical product structure.
Product Structure
Hybrid Product Organization
The system supports both flat and hierarchical product structures with automatic detection:
Option 1: Flat Structure (Simple)
└── .claude/product/
└── index.md # Single file with all features
Option 2: Hierarchical Structure (Organized)
└── .claude/product/
├── index.md # Product overview and goals
└── domains/
├── authentication/
│ ├── index.md # Domain overview
│ └── features/
│ ├── login.md
│ ├── register.md
│ └── logout.md
├── user-management/
│ ├── index.md
│ └── features/
│ ├── profile.md
│ └── settings.md
└── dashboard/
├── index.md
└── features/
└── main-dashboard.md
Auto-Detection Algorithm
if exists(".claude/product/domains/*/index.md"):
structure_type = "hierarchical"
product_root = ".claude/product"
use_domains = true
else:
if exists(".claude/product/index.md"):
structure_type = "flat"
product_root = ".claude/product"
use_domains = false
else:
error("No product specification found")
Priority Order:
- Hierarchical (
.claude/product/domains/*/index.md) - preferred for organized projects
- Flat (
.claude/product/index.md) - simple flat format for projects without domains
Parsing Product Structure
For Hierarchical Structure
domain_files = Glob(".claude/product/domains/*/index.md")
if domain_files.length > 0:
structure_type = "hierarchical"
Read .claude/product/index.md
for domain_file in domain_files:
Read domain_file
domain_name = extract_from_path(domain_file)
feature_files = Glob(".claude/product/domains/{domain_name}/features/*.md")
for feature_file in feature_files:
Read feature_file
For Flat Structure
if exists(".claude/product/index.md"):
product_file = ".claude/product/index.md"
else:
error("No product specification found")
Read product_file
State File: .agentful/completion.json
Hierarchical Schema
{
"domains": {
"domain-id": {
"name": "Domain Name",
"priority": "CRITICAL|HIGH|MEDIUM|LOW",
"status": "pending|in_progress|complete|blocked",
"score": 0-100,
"started_at": "2026-01-18T00:00:00Z",
"completed_at": "2026-01-18T01:00:00Z",
"features": {
"feature-id": {
"name": "Feature Name",
"priority": "CRITICAL|HIGH|MEDIUM|LOW",
"status": "pending|in_progress|complete|blocked",
"score": 0-100,
"started_at": "2026-01-18T00:00:00Z",
"completed_at": "2026-01-18T01:00:00Z",
"subtasks": {
"subtask-id": {
"name": "Subtask Name",
"status": "pending|in_progress|complete",
"completed_at": "2026-01-18T01:00:00Z"
}
},
"notes": "Optional notes about progress"
}
},
"notes": "Optional notes about domain progress"
}
},
"gates": {
"tests_passing": false,
"no_type_errors": false,
"no_dead_code": false,
"coverage_80": false,
"security_clean": false
},
"overall": 0,
"last_updated": "2026-01-18T00:00:00Z"
}
Flat Schema (Legacy Support)
For products without domain structure, the flat schema is still supported:
{
"features": {
"feature-id": {
"status": "pending|in_progress|complete|blocked",
"score": 0-100,
"started_at": "2026-01-18T00:00:00Z",
"completed_at": "2026-01-18T01:00:00Z",
"notes": "Optional notes about progress"
}
},
"gates": {
"tests_passing": false,
"no_type_errors": false,
"no_dead_code": false,
"coverage_80": false,
"security_clean": false
},
"overall": 0,
"last_updated": "2026-01-18T00:00:00Z"
}
Reading Progress
Hierarchical Structure
Read .agentful/completion.json
Flat Structure (Legacy)
Read .agentful/completion.json
Updating Progress
Updating Hierarchical Structure
When a subtask is completed:
{
"domains": {
"authentication": {
"features": {
"login": {
"subtasks": {
"login-ui": {
"status": "complete",
"completed_at": "2026-01-18T01:00:00Z"
},
"login-api": {
"status": "in_progress"
}
},
"score": 50,
"status": "in_progress"
}
},
"score": 50,
"status": "in_progress"
}
}
}
When a feature is completed (all subtasks done):
{
"domains": {
"authentication": {
"features": {
"login": {
"status": "complete",
"score": 100,
"completed_at": "2026-01-18T02:00:00Z",
"notes": "Login UI and API fully implemented with tests"
}
},
"score": 33,
"status": "in_progress"
}
}
}
When starting work on a feature:
{
"domains": {
"authentication": {
"features": {
"register": {
"status": "in_progress",
"score": 0,
"started_at": "2026-01-18T02:30:00Z",
"subtasks": {
"register-ui": {
"status": "in_progress"
},
"register-api": {
"status": "pending"
}
}
}
},
"score": 22,
"status": "in_progress"
}
}
}
Updating Flat Structure (Legacy)
When work is completed on a feature:
{
"features": {
"authentication": {
"status": "complete",
"score": 100,
"started_at": "2026-01-18T00:00:00Z",
"completed_at": "2026-01-18T01:30:00Z",
"notes": "JWT authentication fully implemented with tests"
}
}
}
When starting work on a feature:
{
"features": {
"user-profile": {
"status": "in_progress",
"score": 0,
"started_at": "2026-01-18T01:30:00Z"
}
}
}
When progress is made:
{
"features": {
"user-profile": {
"status": "in_progress",
"score": 45,
"notes": "Backend service complete, frontend pending"
}
}
}
Calculating Overall Score
Hierarchical Score Calculation
function calculateHierarchicalScore(domains, gates) {
let totalDomainScore = 0;
let domainCount = 0;
for (const [domainId, domain] of Object.entries(domains)) {
const features = domain.features;
if (!features || Object.keys(features).length === 0) continue;
let featureTotal = 0;
let featureCount = 0;
for (const [featureId, feature] of Object.entries(features)) {
if (feature.subtasks) {
const subtasks = Object.values(feature.subtasks);
const completed = subtasks.filter(st => st.status === 'complete').length;
feature.score = Math.round((completed / subtasks.length) * 100);
}
featureTotal += feature.score;
featureCount++;
}
domain.score = Math.round(featureTotal / featureCount);
totalDomainScore += domain.score;
domainCount++;
}
const gateScores = Object.values(gates).map(g => g ? 100 : 0);
const gateScore = gateScores.reduce((a, b) => a + b, 0) / gateScores.length;
const domainScore = domainCount > 0 ? totalDomainScore / domainCount : 0;
const overall = Math.round((domainScore * 0.8) + (gateScore * 0.2));
return { overall, domainScore, gateScore };
}
Priority Weights:
| Priority | Weight |
|---|
| CRITICAL | 1.5x |
| HIGH | 1.2x |
| MEDIUM | 1.0x |
| LOW | 0.5x |
Weighted score calculation:
function calculateWeightedScore(domains) {
let totalWeightedScore = 0;
let totalWeight = 0;
const priorityWeights = {
CRITICAL: 1.5,
HIGH: 1.2,
MEDIUM: 1.0,
LOW: 0.5
};
for (const [domainId, domain] of Object.entries(domains)) {
const weight = priorityWeights[domain.priority] || 1.0;
totalWeightedScore += domain.score * weight;
totalWeight += weight;
}
return Math.round(totalWeightedScore / totalWeight);
}
Flat Score Calculation (Legacy)
const featureScores = Object.values(features).map(f => f.score);
const featureScore = Math.round(
featureScores.reduce((a, b) => a + b, 0) / featureScores.length
);
const gateScores = Object.values(gates).map(g => g ? 100 : 0);
const gateScore = gateScores.reduce((a, b) => a + b, 0) / gateScores.length;
const overall = Math.round((featureScore * 0.8) + (gateScore * 0.2));
const gatePenalty = Object.values(gates).filter(g => !g).length * 5;
const finalScore = Math.max(0, overall - gatePenalty);
Quality Gates
Each gate must pass for production readiness:
| Gate | Check | Command |
|---|
| tests_passing | All tests pass | npm test |
| no_type_errors | No TypeScript errors | npx tsc --noEmit |
| no_dead_code | No unused code | npx knip |
| coverage_80 | Test coverage ≥ 80% | npm test -- --coverage |
| security_clean | No secrets/vulnerabilities | npm audit |
Feature Status Values
| Status | Meaning | Score Range |
|---|
| pending | Not started | 0 |
| in_progress | Work in progress | 1-99 |
| complete | Fully done and validated | 100 |
| blocked | Waiting on decision/dependency | any |
Integration with Product Structure
Parsing Hierarchical Product Structure
Parse .claude/product/index.md and all domain/feature files:
<!-- .claude/product/index.md -->
# My Product
## Domain: Authentication
Priority: CRITICAL
## Domain: User Management
Priority: HIGH
<!-- .claude/product/domains/authentication/index.md -->
# Authentication Domain
Provides user authentication and authorization features.
## Features
- User Registration
- User Login
- Password Reset
<!-- .claude/product/domains/authentication/features/login.md -->
# Feature: User Login
Priority: CRITICAL
## Subtasks
1. Create login form UI
- Status: pending
- Acceptance: [ ] Email field, [ ] Password field, [ ] Submit button
2. Implement login API
- Status: pending
- Acceptance: [ ] POST /api/auth/login, [ ] JWT generation, [ ] Error handling
Map to completion.json:
{
"domains": {
"authentication": {
"name": "Authentication",
"priority": "CRITICAL",
"status": "in_progress",
"score": 33,
"features": {
"login": {
"name": "User Login",
"priority": "CRITICAL",
"status": "in_progress",
"score": 50,
"subtasks": {
"login-ui": {
"name": "Create login form UI",
"status": "complete",
"completed_at": "2026-01-18T01:00:00Z"
},
"login-api": {
"name": "Implement login API",
"status": "pending"
}
}
}
}
}
}
}
Parsing Flat Product Structure
Parse .claude/product/index.md to extract feature list:
## Features
### 1. Authentication - CRITICAL
**Description**: User login with JWT
**Acceptance**:
- [x] Login endpoint
- [x] Registration endpoint
- [x] JWT token generation
- [ ] Refresh token flow
Map to completion.json:
{
"features": {
"authentication": {
"status": "in_progress",
"score": 75,
"acceptance": {
"login_endpoint": true,
"registration_endpoint": true,
"jwt_generation": true,
"refresh_token": false
}
}
}
}
Usage
Auto-Detection First
Always detect structure type before any operation:
domains_found = Glob(".claude/product/domains/*/index.md")
product_index_exists = exists(".claude/product/index.md")
if domains_found:
use_hierarchical_tracking()
else if product_index_exists:
use_flat_tracking()
else:
error("No product specification found")
For Hierarchical Structure
When orchestrator asks for progress update:
- Detect structure type (domains found → hierarchical)
- Read
.claude/product/index.md to discover domains
- Use Glob to find all
.claude/product/domains/*/index.md files
- For each domain, read its index and discover features
- Read
.agentful/completion.json
- Calculate overall percentage with weighted hierarchy
- Identify next priority subtask within highest priority domain
- Check for blocked items
- Report summary with domain/feature/subtask breakdown
When subtask work completes:
- Update subtask status to "complete"
- Add completed_at timestamp
- Recalculate feature score (based on completed subtasks)
- Recalculate domain score (based on feature scores)
- Recalculate overall score (weighted average)
- Write back to completion.json
For Flat Structure
When orchestrator asks for progress update:
- Detect structure type (no domains,
.claude/product/index.md exists → flat)
- Read
.claude/product/index.md for product specification
- Read completion.json
- Calculate overall percentage
- Identify next priority feature
- Check for blocked items
- Report summary
When feature work completes:
- Update feature status to "complete"
- Set score to 100
- Add completed_at timestamp
- Recalculate overall score
- Write back to completion.json
Structure Compatibility
| Structure Type | Detection | Product File | Completion Schema | Tracking Method |
|---|
| Hierarchical | .claude/product/domains/*/index.md exists | .claude/product/index.md | Nested domains object | Track at subtask → feature → domain levels |
| Flat | .claude/product/index.md exists | .claude/product/index.md | Flat features object | Track at feature level |