TeamLead Project Diagnostic Skill
SkillDocs & knowledgeProject health diagnostic, analyzes git history, documentation drift, code health, and regression patterns. Produces DIAGNOSTIC-REPORT.md. Use when: everything is broken, need to understand what's happening, project health check, diagnose issues, or the user says "/nacl-tl-diagnose".
Use TeamLead Project Diagnostic Skill in Claude, ChatGPT or Ahel Desktop
Free. Sign in, add TeamLead Project Diagnostic Skill and connect your AI. About a minute.
Also: Claude Code · Cursor · Codex
Then ask your AI: use the TeamLead Project Diagnostic Skill
Details
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; Ahel provides instructions and does not run this skill.
No other account needed.
Add Ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
What this skill tells your AI
The instructions your AI receives, as published by itsalt/nacl in nacl-tl-diagnose/SKILL.md and read by Ahel’s review.
Your Role
You are a project health diagnostician. When everything seems broken and nobody understands what's happening — you analyze the project systematically: git history, documentation state, code health, regression patterns. You produce a diagnostic report with actionable recommendations.
You do NOT fix anything. You diagnose and recommend which skill to run next.
Key Principle: Data-Driven Diagnosis
Don't guess — measure.
Don't fix — diagnose.
Don't use one method — use parallel agents.
Invocation
/nacl-tl-diagnose # full analysis (default: 7 days)
/nacl-tl-diagnose --since=5d # specific time period
/nacl-tl-diagnose --since=2026-03-21 # from specific date
/nacl-tl-diagnose --focus=interview # focus on specific area
/nacl-tl-diagnose "nothing works after deploy" # with problem description
Workflow: 4 Steps
Step 1: DATA COLLECTION (3 parallel agents)
Launch 3 agents via Agent tool IN PARALLEL (single message):
Agent 1: Git Health
Project: [PROJECT_PATH]
Period: [--since or default 7d]
Collect:
1. git log --since=[date] --oneline --stat
→ Full list of commits with changed files
2. Classify each commit:
- fix: message starts with "fix:" or contains "fix"
- feat: "feat:" or "feature"
- refactor: "refactor:"
- docs: "docs:" or changes only in docs/
- deploy: changes in .github/, deploy/, Dockerfile
- merge: "Merge" or "merge:"
- chore: everything else
3. Metrics:
- Total commits
- Fix-to-feature ratio (fix / feat)
- Fix-to-total ratio (fix / total)
4. Regression signals:
- Files with 3+ modifications in the period (hot files)
- For each hot file: list of commits in chronological order
- Regression chains: commit A fixes file X,
commit B fixes file X again (distance < 5 commits)
5. Documentation sync:
- Commits that change src/ but NOT docs/ or .tl/ (code-only fixes)
- Commits that change BOTH src/ AND (docs/ or .tl/) (doc-synced commits)
- Fix-to-Doc Ratio: (doc-synced fixes) / (total fixes)
Note: "docs" includes both docs/ directory AND .tl/ task files
Return: JSON with metrics + hot files list + regression chains
Agent 2: Documentation Health
Project: [PROJECT_PATH]
Collect:
1. Last modification date for each file in docs/:
git log -1 --format="%ai" -- [filepath]
2. .tl/status.json:
- Incomplete tasks (status != "done")
- Tasks with stale statuses (unchanged > 7 days)
3. .tl/changelog.md:
- Last 10 entries
- Are there entries for the current period?
4. Documentation lag:
- For each UC in docs/14-usecases/:
- Last modification date of UC-spec
- Last modification date of related code files
- Lag = code_date - doc_date (in days)
5. Doc stubs/placeholders:
- Files in docs/ containing TODO, TBD, or placeholder text
- Empty or very short (< 100 bytes) UC specs
- UCs listed in _uc-index.md but missing their file
6. Graph staleness (first-class drift signal — read drift FROM the graph,
not inferred from file dates). Via mcp__neo4j__read-cypher:
MATCH (n) WHERE coalesce(n.review_status,'current')='stale'
RETURN labels(n)[0] AS type, n.id AS id, n.stale_origin AS caused_by,
n.stale_since AS since
- Count stale nodes; bucket by stale_origin; note the oldest stale_since.
- A non-empty result means an upstream change (UC/entity/endpoint) was made
but its dependents (typically Tasks) were never re-synced via /nacl-tl-plan.
- If Neo4j is unavailable, mark this probe unavailable (do not infer).
Return: JSON with doc ages, lag scores, stale items, placeholders, stale_nodes
Agent 3: Code Health
Project: [PROJECT_PATH]
Monorepo detection:
Check for sub-projects by looking for package.json in immediate
subdirectories (frontend/, backend/, packages/*, apps/*).
If found, run build/test commands in EACH sub-project separately.
If not found, run at project root.
Collect:
1. Build status:
For each sub-project (or root):
- Read the workspace's declared build command from
`package.json.scripts.build` (or the closest declared equivalent for
non-Node workspaces, e.g. `pyproject.toml` `tool.poetry.scripts`).
- If declared, run the declared command and capture the last 20 lines:
declared_build_cmd 2>&1 | tail -20
- If `scripts.build` is undeclared:
Record component status as `build: NO_INFRA (scripts.build undeclared)`.
Do NOT fall back to `npm run build`, `make`, or any other invented
command — emit `NO_INFRA` and continue with the next sub-project.
- If the declared command exits non-zero with a parse/loader error
(config missing, runner crash before any task runs):
Record component status as `build: RUNNER_BROKEN (<reason>)`.
Record: per sub-project, one of: `pass` / `fail` / `NO_INFRA` / `RUNNER_BROKEN`.
2. Test status:
For each sub-project (or root):
- Read the workspace's declared test command from
`package.json.scripts.test` (or the closest declared equivalent).
- If declared, run the declared command and capture the last 30 lines:
declared_test_cmd 2>&1 | tail -30
Record: total passed, total failed, which test files fail.
- If `scripts.test` is undeclared:
Record component status as `test: NO_INFRA (scripts.test undeclared)`.
Do NOT fall back to `npm test` or any other invented command.
- If the declared command runs but `tests_collected == 0` despite test
files matching the runner's pattern, OR exits non-zero with a runner
crash before collection:
Record component status as `test: RUNNER_BROKEN (<reason>)`.
3. Stub markers scan:
Search in src/ (excluding node_modules/, dist/, test files):
- TODO, FIXME, HACK — count by severity
- throw new Error("Not implemented")
- as any (TypeScript)
- console.log (in production code)
- Placeholder data (Lorem ipsum, test@test.com)
4. TypeScript errors:
- Read the workspace's declared typecheck command from
`package.json.scripts.typecheck` (or `scripts.tsc`, `scripts.lint:types`).
- If declared, run the declared command:
declared_typecheck_cmd 2>&1 | tail -30
- If undeclared:
Record component status as `typecheck: NO_INFRA (no declared typecheck command)`.
Do NOT fall back to `npx tsc --noEmit`.
5. Dependency health (if time permits):
- Read the declared audit command (e.g. `scripts.audit`) if present;
otherwise record `audit: NO_INFRA (no declared audit command)`. The
skill MUST NOT invent `npm audit` if the workspace has not declared it.
Return: JSON with build/test/typecheck/audit status per sub-project. Each
component is one of: `pass` / `fail` / `NO_INFRA` / `RUNNER_BROKEN` —
never a synthetic measurement and never a 0.5 fill.
Agent 4 — Server Health (optional)
Запускать только если config.yaml → vps И config.yaml → deploy заполнены.
Collect:
1. Staging health: `curl -sf {deploy.staging.url}{deploy.staging.health_endpoint} --max-time 10`
2. Production health: `curl -sf {deploy.production.url}{deploy.production.health_endpoint} --max-time 10`
3. Если VPS SSH доступен (`vps.[env].ip` заполнен):
- `ssh -i {ssh_key} {user}@{ip} "uptime; df -h /; free -m; pm2 status 2>/dev/null || docker ps 2>/dev/null"`
4. Сравнить с ожидаемым состоянием
Output metrics:
- staging_health: UP / DOWN / DEGRADED
- production_health: UP / DOWN / DEGRADED
- staging_disk_usage: percentage
- staging_memory_usage: percentage
- production_disk_usage: percentage
- production_memory_usage: percentage
Step 1b: AGGREGATION (after all three agents return)
Wait for all three agents to complete before proceeding.
On completion, evaluate each agent's output:
For each agent result:
- If the agent returned valid JSON with required fields → status: success
- If the agent returned an error, empty output, or missing required fields → status: failed
Aggregate status:
- All three succeeded → Data completeness: complete
- One or more failed → Data completeness: partial (Agent #N failed: <reason>)
Record this status in a variable COMPLETENESS_STATUS for inclusion in the final report.
Partial-failure handling:
IF Agent 1 failed:
- git metrics, fix_ratio, regression_ratio, regression_chains → unavailable
- Mark those metric rows as "N/A (git data unavailable)"
IF Agent 2 failed:
- doc ages, doc lag, placeholders → unavailable
- Mark those metric rows as "N/A (doc data unavailable)"
IF Agent 3 failed:
- build_pass, test_pass_rate, stub counts → unavailable
- Mark those metric rows as "N/A (code data unavailable)"
Proceed with analysis on whatever data IS available.
Do NOT abort the diagnostic — a partial report is better than no report.
Step 2: ANALYSIS (main context)
Receive results from 3 agents. Aggregate:
2.1 Metrics Calculation
Output the metrics table in the user's language. Example structure:
┌───────────────────────────────────────────────┐
│ PROJECT HEALTH METRICS │
├───────────────────────────────┬───────────────┤
│ Analysis period │ [date - date] │
│ Total commits │ N │
│ Fix commits │ N (X%) │
│ Fix-to-Doc Ratio │ X% │
│ Hot files (3+ changes) │ N files │
│ Regression chains │ N chains │
│ Avg chain length │ X commits │
│ Max chain length │ X commits │
│ Documentation lag (avg) │ X days │
│ Doc placeholders │ N files │
│ Build status │ ✓/✗ │
│ Test status │ X passed / Y failed │
│ Stub markers │ C critical, W warning │
└───────────────────────────────┴───────────────┘
2.2 Health Score (0-100)
Variable definitions:
fix_ratio = fix_commits / total_commits (0.0 – 1.0)
→ not_assessable: git data unavailable (if Agent 1 failed)
fix_to_doc_ratio = doc_synced_fixes / total_fixes (0.0 – 1.0)
where "doc-synced" = commit touches both src/ and (docs/ or .tl/)
→ not_assessable: git data unavailable (if Agent 1 failed)
regression_ratio = fix_commits_in_regression_chains / total_fix_commits (0.0 – 1.0)
where "in chain" = file was fixed 2+ times within 5 consecutive commits
→ not_assessable: git data unavailable (if Agent 1 failed)
build_pass = 1 if ALL sub-project builds succeed, else 0
→ not_assessable: code agent unavailable (if Agent 3 failed)
test_pass_rate = tests_passed / tests_total (0.0 – 1.0)
→ not_assessable: no test infra (if Agent 3 reports "no tests configured" for ALL sub-projects)
→ not_assessable: code agent unavailable (if Agent 3 failed)
NOTE: do NOT substitute 0.5 — absence of tests is a distinct state,
not a neutral mid-point.
Per-component score breakdown:
Report each component individually:
git_quality_component:
fix_ratio_score = (1 - fix_ratio) × 25 (or not_assessable)
doc_sync_score = fix_to_doc_ratio × 25 (or not_assessable)
regression_score = (1 - regression_ratio) × 20 (or not_assessable)
build_component:
build_score = build_pass × 15 (or not_assessable)
test_component:
test_score = test_pass_rate × 15 (or not_assessable: no test infra)
server_component (if Agent 4 ran):
server_health_score = (staging_up × 0.5 + production_up × 0.5) × 15
where UP=1.0, DEGRADED=0.5, DOWN=0.0
Composite score rule:
IF any component is not_assessable:
- Do NOT produce a single health_score number.
- Instead, produce a per-component breakdown table showing which
components have scores and which are not_assessable.
- State: "Composite score withheld — not all components are assessable."
IF all components are assessable:
health_score =
fix_ratio_score + doc_sync_score + regression_score
+ build_score + test_score
[+ server modifier if Agent 4 ran:
health_score = health_score × 0.85 + server_health_score]
Interpretation:
80-100: Healthy project
60-79: Needs attention (targeted fixes)
40-59: Serious problems (reconcile recommended)
0-39: Critical state (reconcile mandatory)
2.3 Problem Clusters
Grouping algorithm:
- Take all hot files (3+ modifications in period)
- Group by the most specific shared directory or feature keyword:
- Same directory path (e.g.,
routes/interview-chat.ts+hooks/useInterviewChat.ts→ "interview" cluster) - Same feature keyword in filename (e.g.,
auth,payment,session) - Deploy/CI files (
.github/,deploy/,Dockerfile) → always a separate cluster
- Same directory path (e.g.,
- If a file doesn't fit any cluster, assign to "other"
- Sort clusters by total fix count (descending)
For each cluster report:
- Files in the cluster and their modification counts
- Total fix commits touching the cluster
- Number of regression chains within the cluster
- Docs coverage: which UC/spec files exist for this area, when last updated
2.4 Root Cause Hypotheses
Formulate hypotheses based on metrics:
IF fix_to_doc_ratio < 10% AND regression_ratio > 30%:
→ Hypothesis: "Fixes without doc updates cause regression cycles"
Required evidence: cite at least one regression chain where a hot file
was fixed without a corresponding doc/spec commit (show commit SHAs).
Without evidence → label as "candidate hypothesis (unverified)".
IF doc_lag > 7 days for hot files:
→ Hypothesis: "Documentation is outdated, AI assistant works from stale specs"
Required evidence: cite at least one specific file where code_date > doc_date,
showing the commit that drifted and the last doc-update commit (show SHAs and dates).
Without evidence → label as "candidate hypothesis (unverified)".
IF stale_nodes is non-empty:
→ Hypothesis: "An upstream change was made but its dependents were never
re-synced — the graph itself records the drift (review_status='stale')."
This is stronger than file-date inference: the stamp names stale_origin and
stale_since. Recommend /nacl-tl-plan (regenerates stale Tasks) or re-review of
the flagged nodes. Closure (release/conductor) is already blocked while these
persist (sa-validate L8 / release condition #7).
IF doc_placeholders > 3:
→ Hypothesis: "Parts of the system are unspecified, no source of truth"
Required evidence: list the specific placeholder files found (filenames + line sample).
Without evidence → label as "candidate hypothesis (unverified)".
IF build_fail OR test_fail:
→ Hypothesis: "Code doesn't build or tests fail — fix needed before diagnosis"
Required evidence: include the specific error output excerpt (last 5 lines of
build/test stderr) that confirms the failure.
Without evidence → label as "candidate hypothesis (unverified)".
RULE: Every hypothesis emitted in the report MUST include its evidence block.
A hypothesis with no supporting evidence MUST be labeled
"candidate hypothesis (unverified)" rather than a confirmed finding.
Remote mode (multi-user shared graph): when config.yaml graph.mode: remote, the graph is the
canonical source and .tl/status.json is a per-clone local cache. Divergence between the local
status.json and the graph is EXPECTED and benign (it reflects other developers' machines, not
a bug) — report it informationally, do NOT raise it as drift or recommend reconciliation. Keep full
diagnostic weight on stale_nodes (above), which record real upstream changes whose dependents were
never re-synced — those are genuine drift in either mode. See
nacl-tl-core/references/remote-mode-coordination.md.
Step 3: TARGETED GAP-ANALYSIS (1-2 agents)
For the TOP-2 problem clusters, launch agents.
Scope cap: Analyze at most 5 hottest files per cluster (by modification count). This prevents excessive context usage while still capturing the main discrepancies.
Truncation warning: If a cluster has more than 5 files, prepend the following line to that cluster's discrepancy list:
WARNING: Analyzed top-5 of N files in cluster "[CLUSTER_NAME]" — full analysis may reveal additional discrepancies.
(Replace N with the actual cluster file count.)
For cluster [NAME]:
1. Select top-5 files by modification count in the cluster
2. Read current code for these files
3. Read corresponding docs (UC, domain, screen specs)
- If no docs exist for the area, note "MISSING: no spec for [area]"
4. For each file: compare code behavior vs docs description
5. Record specific discrepancies:
- [DOC] file says: "X"
- [CODE] file does: "Y"
- [SEVERITY] critical / high / medium / low
Return: list of discrepancies with severity
Step 4: DIAGNOSTIC REPORT
Generate DIAGNOSTIC-REPORT.md in the project root. Write the report in the user's language.
Report structure:
# Diagnostic Report
**Project:** [name]
**Date:** [date]
**Period:** [since — now]
**Data completeness:** [complete | partial (Agent #N failed: reason)]
**Health Score:** [0-100 (interpretation)] OR **Score withheld — per-component breakdown below**
## 1. Metrics
[table from Step 2.1]
## 2. Regression Chains
[for each chain: commit A → commit B → commit C]
## 3. Problem Clusters
[for each cluster: files, fixes, docs coverage]
## 4. Discrepancies: docs vs code (top)
[from Step 3: specific "doc says X, code does Y"]
[IMPORTANT: for each discrepancy, include the doc file's last modified date
so nacl-tl-reconcile can detect already-fixed items]
## 5. Root Cause Analysis
[hypotheses from Step 2.4]
## 6. Recommendations
### If Health Score >= 60:
- Targeted fixes via /nacl-tl-fix:
1. /nacl-tl-fix "[problem description 1]"
2. /nacl-tl-fix "[problem description 2]"
### If Health Score 40-59:
- /nacl-tl-reconcile --scope=[top cluster]
- Then targeted /nacl-tl-fix for the rest
### If Health Score < 40:
- /nacl-tl-reconcile (full)
- After reconcile: /nacl-tl-stubs --final
- Then /nacl-tl-qa for critical UCs
Pre-finalize checklist — before saving the file, verify every item below is present and non-empty. If any item is missing, fill it or explicitly mark it N/A — data unavailable (reason):
[ ] Data completeness status (complete / partial — must appear at top of report)
[ ] Section 1: Metrics table — all rows present; unavailable rows marked N/A
[ ] Section 2: Regression Chains — present; "None found" is acceptable
[ ] Section 3: Problem Clusters — at least one entry, or "No hot files in period"
[ ] Section 4: Discrepancies — present; truncation warning included if cluster > 5 files
[ ] Section 5: Root Cause Analysis — every hypothesis has an evidence block or is
labeled "candidate hypothesis (unverified)"
[ ] Section 6: Recommendations — present and tied to the actual health score or
component breakdown
[ ] Health score or per-component breakdown — single number only if all components
are assessable; otherwise per-component table with not_assessable labels
Only after all items are checked: present the report to the user and save as DIAGNOSTIC-REPORT.md.
Output Language
Detect the user's language from:
- The language of their invocation message (highest priority)
- The
docs/content language (if invocation is ambiguous) - Default to English if unclear
Write the DIAGNOSTIC-REPORT.md in the detected language. Internal agent prompts remain in English regardless.
Output Artifact
File: DIAGNOSTIC-REPORT.md in the project root.
This file is used by:
/nacl-tl-reconcile— as input for Phase 1- The user — for understanding the project state
- History — for before/after comparison across reconcile runs
Signals
- GitHub stars
- 27
- Forks
- 4
- Last commit
- Sep 2026
Advanced
- Item type
- skill
- Key
nacl-tl-diagnose- Source
- github.com/itsalt/nacl
More in Docs & knowledge
Skill · mattpocock
More in Docs & knowledgecanvas-design
Skill · anthropics
More in Docs & knowledgedoc-coauthoring
Skill · anthropics
More in Docs & knowledgepopups
Skill · coreyhaines31
More in Docs & knowledgewriting-for-agents
Skill · mattpocock
More in Docs & knowledgespec-driven-development
Skill · addyosmani
More in Docs & knowledge