Skip to content
Back to skills

Tad Maintain

ASecurity

TAD document health check and synchronization. CHECK/SYNC modes for handoff cleanup and maintenance.

  • 3 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 6, 2026
ai-agentsgobashtestinggit

Works with

  • claude code
  • terminal

Security analysis

A100/100

Scanned October 6, 2026

npx -y skills add Sheldon-92/TAD --skill tad-maintain --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Tad Maintain?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Tad Maintain
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/sheldon-92-tad-maintain/badge)](https://www.skillsdirectory.com/skills/sheldon-92-tad-maintain)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: tad-maintain
description: TAD document health check and synchronization. CHECK/SYNC modes for handoff cleanup and maintenance.
---

# TAD Maintain Command

When this command is used, perform document health check and synchronization.

平台绑定交互决策(cross-harness binding):本文件及其 references 中所有
AskUserQuestion 调用是「交互决策契约」而非具体工具——当前 harness 有该工具
(Claude Code)→ 直接调用;无该工具(Codex 等)→ 以编号纯文本列出全部选项
(1. … / 2. … / 3. …)并**停止等待用户输入**,用户以编号或自由文本作答;
禁止代答、禁止把选项折叠成默认值继续执行。SAFETY 门控的调用点(人工审批 /
归档确认 / 权限升级确认类)无论何种 harness 都必须获得真人作答后才能继续。
非交互执行模式(如 codex exec)→ 视为无人可答,按 blocked 停止并上报,
不得自选默认值;已按 YOLO/预授权模式运行且该决策点有书面预授权记录 →
按其协议处理,不适用本条 blocked 分支。

## Mode

- Default (no argument or `full`): FULL mode - comprehensive check + sync
- When called with `check` context from agent activation: CHECK mode - read-only
- When called with `sync` context from *accept: SYNC mode - scoped write operations

**CHECK mode**: MUST NOT modify any files. Read-only scan and report only.
**SYNC mode**: Scoped to the specific handoff being accepted + NEXT.md cleanup.
**SYNC mode parameter**: `target_slug` - the canonical slug of the handoff just accepted.
  When provided, Step 2 Handoff Lifecycle Audit processes ONLY the matching handoff (skip others).
  When not provided (fallback), process all active handoffs (same as FULL mode behavior).
**FULL mode**: CHECK + broad SYNC across all documents.

## Step 1: Gather Current State

Read these to establish baseline:
1. `.tad/version.txt` → current version string
2. `.tad/config.yaml` (first 10 lines) → config version
3. `ls .tad/active/handoffs/` → list active handoff files
4. `ls .tad/archive/handoffs/` → list archived files
5. `ls .tad/active/epics/` → list active epic files
6. `ls .tad/archive/epics/` → list archived epic files
7. `NEXT.md` → count lines, read content
8. `PROJECT_CONTEXT.md` → check if exists

## Step 1.5: Drift Detection (Phase 1 P1.2, 2026-04-24)

Run drift detection BEFORE the handoff lifecycle audit (Step 2). Drift findings are
**advisory** (smoke alarm only) — they never auto-modify files; they surface patterns
that need human review.

### Invocation

```bash
bash .tad/hooks/lib/drift-check.sh check-all
```

The script snapshots `.tad/active/handoffs/` ONCE at entry and runs 4 subchecks
serially against that snapshot. Output on stdout is one JSON line per finding;
stderr has human-readable status lines `[drift-check] {subcheck} {handoff} {status}`.

### Subchecks Run

| Subcheck | What it detects | Evidence source |
|----------|----------------|-----------------|
| `slug_consistency` | handoff filename slug not in Required Evidence Manifest paths | 某应用项目 2026-04-11 + toy layer2-audit FN 2x in 8d |
| `zombie_handoffs`  | git commit found for slug + COMPLETION archived + handoff still active | 某应用项目 code-quality.md:36 |
| `supersedes_chains` | `Supersedes:` field points to a handoff still in active/ | Next Guest 3 same-day handoffs |
| `ghost_tasks`      | housekeeping/sync/cleanup slug missing `grounded_state` frontmatter | toy 2026-04-24 |

### Report Inclusion

Aggregate drift findings in the CHECK-mode report as a new top-level section
**before** `RECOMMENDED ACTIONS`. Example:

```
DRIFT FINDINGS (advisory — human review required)
  [icon] slug_consistency: {N} drift | {N} info | {N} ok
  [icon] zombie_handoffs:  {N} drift | {N} info | {N} ok
  [icon] supersedes_chains: {N} drift
  [icon] ghost_tasks:      {N} drift

  TOP DRIFTS:
    - {handoff}: {subcheck}: {message}. Suggested: {suggested_action}
    - ...
```

### Modes

- **CHECK**: Run drift detection, report findings (read-only). Do NOT auto-archive
  supersedees or move zombies — Criterion C/D-style interactive confirmation still applies
  in SYNC/FULL modes via the Step 2 Handoff Lifecycle Audit.
- **SYNC**: Drift findings are displayed alongside lifecycle audit, but SYNC does
  not auto-apply drift suggestions. User may run Step 2 actions separately.
- **FULL**: Same as SYNC + include drift findings.

### Config

`.tad/config-workflow.yaml → drift_check:` controls:
- `zombie_window_days` (default 60) — how far back git log is scanned
- `ghost_task_prefixes` (default `[housekeeping, sync, rsync, cleanup, maintenance, audit, refresh]`)

### Failure isolation

- If git is unavailable → `zombie_handoffs` emits `status:error`, the other 3 subchecks
  still run to completion.
- jq missing → the whole tool fails with exit 1 (jq is required for safe JSON emission).
- Any subcheck internal exception → caught by the dispatch's `|| _emit error` safety net.

## Step 1.6: Brain-Index Freshness (WARN-only, advisory)

Compare mtime of `.tad/brain-index.md` against the newest file in
`.tad/project-knowledge/`. This check is strictly advisory — it NEVER fails
a gate and NEVER blocks acceptance (L1 "Knowledge Is Forged at Distill").

```bash
if [ -f .tad/brain-index.md ] && [ -d .tad/project-knowledge ]; then
  if find .tad/project-knowledge -type f -newer .tad/brain-index.md -print -quit 2>/dev/null | grep -q .; then
    echo "⚠️ brain-index.md is older than project-knowledge (run bash .tad/hooks/lib/brain-index-gen.sh to refresh)"
  fi
fi
```

### Modes

- **CHECK**: Print the advisory warning if stale (exit 0 — WARN-only, never fail).
- **SYNC**: Automatically run the soft rebuild after lifecycle actions complete:
  ```bash
  bash .tad/hooks/lib/brain-index-gen.sh >/dev/null 2>&1 || true
  ```
- **FULL**: Same as SYNC.

## Step 2: Handoff Lifecycle Audit

For each file in `.tad/active/handoffs/`:
(SYNC mode with target_slug: skip files whose extracted slug does not match target_slug)

### Step 2a: Extract Canonical Slug

Different naming formats exist. Extract a slug for matching:

| Format | Example | Extracted Slug |
|--------|---------|----------------|
| `HANDOFF-{date}-{slug}.md` | `HANDOFF-20260126-multi-platform-init.md` | `multi-platform-init` |
| `{date}_{time}_{version}_{taskid}_{slug}_{type}.md` | `20260126_0043_v1.0_TASK-20260126-001_blake-ralph-fusion_design.md` | `blake-ralph-fusion` |
| `COMPLETION-{date}-{slug}.md` | `COMPLETION-20260126-blake-ralph-fusion.md` | `blake-ralph-fusion` |

**Extraction rules:**
1. Strip file extension `.md`
2. If starts with `HANDOFF-` or `COMPLETION-`: remove prefix and date, remaining = slug
3. If long format: extract the segment between task-id and type (e.g., between `TASK-YYYYMMDD-NNN_` and `_design`)
4. Normalize: lowercase, keep hyphens

### Step 2b: Match Against Archive

For each active handoff's slug, search `.tad/archive/handoffs/` for:

**Criterion A (COMPLETED)**: A file matching `COMPLETION-*{slug}*` exists in archive.
→ Action: Mark as COMPLETED.

**Criterion B (SUPERSEDED)**: A file with the same slug but higher version number exists in archive.
→ Action: Mark as STALE.

**Criterion C (AGE_STALE)**: Handoff has been active longer than `handoff_lifecycle.stale_age_days` (default 7).
→ Calculate age: extract date from filename (YYYYMMDD), compare with today.
→ If age > threshold AND Criterion A/B did not match: Mark as POTENTIALLY_STALE.

**Criterion D (TOPIC_SUPERSEDED)**: An archived handoff's topic overlaps with this active handoff.
→ For each active handoff not matched by A/B/C:
  1. Read the active handoff's first 15 lines to extract title and Executive Summary keywords.
  2. Scan archived handoffs (created within `handoff_lifecycle.cross_reference_window_days`, default 30 days).
  3. Read each archive candidate's first 15 lines, compare title/summary keywords.
  4. Read `common_words_exclude` list from `.tad/config-workflow.yaml` → `document_management.handoff_lifecycle.common_words_exclude`.
     If significant keyword overlap found (≥2 shared topic words, excluding words in the `common_words_exclude` list):
     Mark as POTENTIALLY_SUPERSEDED and record the matching archive file.

**No match found by any criterion**: Keep as ACTIVE (in progress).

### Step 2c: Actions (SYNC/FULL mode only)

**Write safety - two-phase approach:**
1. First: Verify destination in `.tad/archive/handoffs/` does not already have a file with the same name
2. If name conflict: append `-dup-{timestamp}` suffix to avoid overwrite
3. Move file: copy to archive first, then delete from active
4. If copy fails: abort, report error, do NOT delete source

Actions by status:
- COMPLETED → move to `.tad/archive/handoffs/`
- STALE → verify archive has newer version (re-read archive directory to confirm), then delete from active. If verification fails, keep in active and report error.
- POTENTIALLY_STALE or POTENTIALLY_SUPERSEDED (FULL mode only) → **interactive confirmation required**:
  1. Use `AskUserQuestion` to present findings to the user:
     - Show handoff filename, age in days, and slug
     - For POTENTIALLY_SUPERSEDED: show the matching archived handoff filename
     - Options: "Archive" (move to archive), "Keep" (leave as active), "Delete" (remove, work was absorbed elsewhere)
  2. If user says Archive → move to `.tad/archive/handoffs/` (two-phase safety)
  3. If user says Keep → leave in place, no action
  4. If user says Delete → delete from active (no archive copy needed)
  5. In CHECK/SYNC mode: only report as finding, do NOT prompt or take action
- ACTIVE → no action (leave in place)

### Prohibitions

1. **NEVER use file modification time (mtime)** to determine handoff age. Always extract date from filename (YYYYMMDD format). File mtime is unreliable (git operations, copies, editor saves change it).
2. **Criterion C and D MUST NOT auto-archive.** They always require interactive user confirmation via AskUserQuestion. Only Criterion A (COMPLETED) and B (SUPERSEDED) may auto-archive in SYNC mode.

### Step 2d: Idempotency Check

Before any move/delete, verify the source file still exists in `active/`. If already moved (e.g., by a concurrent run), skip silently.

## Step 2e: Epic Lifecycle Audit

For each file in `.tad/active/epics/`:

### Step 2e-i: Parse Epic

1. Read the Epic file
2. Extract Phase Map table
3. For each phase, determine status (⬚ Planned / 🔄 Active / ✅ Done)
4. Check if phase has a linked handoff filename

### Step 2e-ii: Run 6 Check Types

**Check 1 - STALE**: All phases are ✅ Done but Epic is still in `active/epics/`.
→ Detection: Parse Phase Map, count statuses. If all ✅ → STALE.
→ Action (SYNC/FULL): Move to `.tad/archive/epics/` (two-phase safety).

**Check 2 - ORPHAN**: No linked handoffs AND Epic age > `stale_age_days`.
→ Detection: Phase Map has no handoff filenames filled in, AND file date > threshold.
→ Action (FULL only): AskUserQuestion - "Epic {name} has no linked handoffs and is {N} days old. Archive, keep, or delete?"

**Check 3 - DANGLING_REF**: Phase Map references a handoff file that doesn't exist.
→ Detection: For each handoff filename in Phase Map, check if file exists in `active/handoffs/` or `archive/handoffs/`.
→ Action (all modes): Report WARNING. Do not auto-fix.

**Check 4 - BACK_REF_MISMATCH**: A handoff has an `**Epic**` field referencing this Epic, but the Epic's Phase Map doesn't list that handoff.
→ Detection: Scan active handoffs AND recently archived handoffs (within `cross_reference_window_days`) for Epic field, cross-reference with Phase Map.
→ Action (all modes): Report WARNING. Do not auto-fix.

**Check 5 - STUCK**: A phase is 🔄 Active but its linked handoff was created > `stale_age_days` ago, OR an Active phase has no linked handoff at all.
→ Detection: Find Active phases, check handoff creation date from filename. If Active phase has no linked handoff (dash or empty), treat as STUCK immediately (an Active phase without a handoff is abnormal).
→ Action (all modes): Report WARNING. Remind user to check progress.

**Check 6 - OVER_ACTIVE**: More than 1 phase in the same Epic is 🔄 Active.
→ Detection: Count Active phases per Epic. If > 1 → violation.
→ Action (all modes): Report ERROR. This violates concurrent control rules.

**Check 7 - OVER_LIMIT**: More than `max_active_epics` (default 3) Epics in `active/epics/`.
→ Detection: Count Epic files in `.tad/active/epics/` (excluding `.gitkeep`). If > 3 → warning.
→ Action (all modes): Report WARNING. Suggest completing existing Epics before creating new ones.

### Step 2e-iii: Actions (SYNC/FULL mode only)

- STALE → move to `.tad/archive/epics/` (two-phase safety: copy first, verify, then delete source)
- ORPHAN → FULL mode only, interactive confirmation via AskUserQuestion
- All others → report only, do not auto-fix

## Step 3: NEXT.md Maintenance

### Step 3a: Read Thresholds from Config

Read `.tad/config.yaml` section `next_md_maintenance.size_limits`:
- `warning_threshold` (default 400)
- `max_lines` (default 500)

### Step 3b: Check

1. Count total lines in NEXT.md
2. Parse sections by `## ` headers
3. Classify each section:

| Section Pattern | Classification | Archive? |
|-----------------|---------------|----------|
| `## 已完成 (DATE)` or `## Completed (DATE)` | Completed | Yes, if DATE > 7 days ago |
| `## 今天` or `## Today` | Active | Never |
| `## 本周` or `## This Week` | Active | Never |
| `## In Progress` | Active | Never |
| `## 待定` or `## Pending` | Active | Never |
| `## 阻塞` or `## Blocked` | Active | Never |
| `## vX.X 变更摘要` | Reference | Archive with its parent completed section |
| `## Recently Completed` | Completed | Yes, if oldest entry > 7 days ago |
| Any other `## ` section | Unknown | Flag in report, don't auto-archive |

4. Check if total lines > `warning_threshold`

### Step 3c: Actions (SYNC/FULL mode only)

Only if total lines > `max_lines` (from config):
1. Identify archivable sections (completed > 7 days + their reference tables)
2. Read `.tad/templates/history-md-template.md` for archive format
3. Create or append to `docs/HISTORY.md`:
   - If `docs/HISTORY.md` doesn't exist, create it with template header
   - Append archived sections under `## Week of {date}` heading
4. **Write HISTORY.md first, verify write succeeded**
5. Only then: remove archived sections from NEXT.md
6. Update any stale version references in NEXT.md

If between `warning_threshold` and `max_lines`: report WARNING but do not auto-archive.

## Step 4: PROJECT_CONTEXT.md Sync

### Check:
- File exists?
- If exists: version matches `.tad/version.txt`?

### Actions (SYNC/FULL mode only):

If missing, create with this template (use actual project values):

```markdown
# Project Context - {project_name}

## Current State
- **Version**: {from .tad/version.txt}
- **Last Updated**: {today}
- **Framework**: TAD v{version}

## Active Work
{list each file in .tad/active/handoffs/ with status}

## Recent Decisions
{from last 3 archived handoffs - 1 line summary each}

## Known Issues
{any flagged items from health check}

## Next Direction
{from NEXT.md active sections - top 3 items}
```

If exists but outdated: update version and Active Work section only.
Keep under 150 lines.

## Step 5: Document Consistency Check

### Checks (all modes):
1. `.tad/version.txt` value == `config.yaml` `version:` field
2. No orphaned design files in `.tad/active/designs/` (designs whose slug has no matching active handoff)
3. Evidence check (FULL mode only): `.tad/evidence/reviews/` files reference existing archived gates

### Actions (FULL mode only):
- Report all inconsistencies
- Auto-fix: if version.txt and config.yaml disagree, report which is newer (by file modification date) and suggest fix, but do NOT auto-fix version mismatches

## Step 6: Health Report Output (Terminal)

**CHECK mode output:**

```
=== TAD Health Check | {date} ===

HANDOFFS
  [icon] {N} active | {N} completed (not archived) | {N} stale | {N} potentially stale (age>{threshold}d) | {N} potentially superseded

EPICS
  [icon] {N} active | {N} stale | {N} orphan | {N} stuck | {N} over-active | {N} dangling refs

DOCUMENTS
  [icon] NEXT.md: {lines} lines {status}
  [icon] PROJECT_CONTEXT.md: {exists/missing}
  [icon] Version: {version.txt} / config: {config version}

PAIR TESTING (.tad/pair-testing/)
  [icon] TEST_BRIEF.md: {exists/none}
  [icon] PAIR_TEST_REPORT.md: {exists (unprocessed!)/none}
  [icon] screenshots/: {exists ({N} files)/none}

{if issues found:}
RECOMMENDED ACTIONS
  1. Run `/tad-maintain` to sync documents
  2. {specific recommendations}
  {if PAIR_TEST_REPORT.md exists:}
  N. Run *test-review in Alex to process pair test report

HEALTH: {OK/WARNING/CRITICAL}
===
```

**SYNC/FULL mode output:**

```
=== TAD Maintain Report | {date} | MODE: {sync/full} ===

HANDOFFS
  [icon] {N} properly archived
  [icon] {N} completed -> archived (this run)
  [icon] {N} stale -> cleaned (this run)
  [icon] {N} user-confirmed -> archived/deleted (this run)
  [icon] {N} active (in progress)

EPICS
  [icon] {N} properly archived
  [icon] {N} stale -> archived (this run)
  [icon] {N} orphan -> user-confirmed (this run)
  [icon] {N} active (in progress)
  [icon] {N} warnings (dangling refs, stuck, back-ref mismatch)

DOCUMENTS
  [icon] config.yaml: v{version}
  [icon] version.txt: v{version}
  [icon] NEXT.md: {lines} lines ({action taken or status})
  [icon] PROJECT_CONTEXT.md: {created/updated/ok}

PAIR TESTING (.tad/pair-testing/)
  [icon] TEST_BRIEF.md: {exists/none}
  [icon] PAIR_TEST_REPORT.md: {exists (unprocessed!)/none}
  [icon] screenshots/: {exists ({N} files)/none}

CONSISTENCY
  [icon] Version alignment: {pass/fail}
  [icon] Active directory: {clean/N orphans}

ACTIONS TAKEN
  1. {description}
  2. {description}
  ...

{if any errors:}
ERRORS
  1. {what failed and why}

HEALTH: {OK/WARNING/CRITICAL} - {summary}
===
```

Icons: use text markers `[OK]` `[WARN]` `[ERR]` `[INFO]` for terminal compatibility.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…