git clone https://github.com/Elkidogz/technical-change-skill
git clone --depth=1 https://github.com/Elkidogz/technical-change-skill ~/.claude/skills/elkidogz-technical-change-skill-tc
SKILL.md/tc — Technical Change Tracker
Track every code change with structured JSON records and accessible HTML output. Ensures AI bot sessions can resume seamlessly when previous sessions expire or are abandoned. Designed for deployment across multiple projects.
First-Use Detection (MANDATORY — Every Session)
At the start of EVERY session, before doing any work:
- Check if
exists in the current working directorydocs/TC/tc_config.json - If it EXISTS: follow the Session Start Protocol in the
section/tc resume - If it does NOT exist: prompt the user:
TC tracking is not initialized in this project. Would you like to set it up? This enables structured change tracking, AI session handoff, and HTML documentation. Run
to get started./tc init - Wait for the user's response. If they agree, run
./tc init - If the user declines, continue without TC tracking for this session.
A global skill is installed at
~/.claude/skills/tc.md to ensure this check runs
in every project, even those that haven't been initialized yet.
Overview
Each Technical Change (TC) is a structured record that documents:
- What changed (files, code, configuration)
- Why it changed (motivation, scope, design decisions)
- Who changed it (human or AI bot session)
- When it changed (revision history with timestamps)
- How it was tested (test cases with evidence from logs)
- Where work stands (session handoff data for bot continuity)
Storage Location
Each project stores TCs at
{project_root}/docs/TC/:
docs/TC/ ├── tc_config.json # Project settings ├── tc_registry.json # Master index ├── index.html # Dashboard ├── records/ │ └── TC-001-MM-DD-YY-name/ │ ├── tc_record.json # System of record │ └── tc_record.html # Human-readable └── evidence/ └── TC-001/ # Log snippets, screenshots
TC Naming Convention
- Parent TC:
(e.g.,TC-NNN-MM-DD-YY-functionality-slug
)TC-001-04-03-26-user-authentication - Sub-TC:
orTC-NNN.A
(letter = revision, number = sub-revision)TC-NNN.A.1 - NNN = sequential number, MM-DD-YY = creation date, slug = kebab-case functionality name
Implementation States
planned → in_progress → implemented → tested → deployed │ │ │ │ │ └→ blocked ←┘ └→ in_progress ←──────┘ │ │ │ (rework/hotfix) │ │ └→ paused → in_progress │ │ │ │ └──────→└→ voided (terminal — cancelled) └→ voided
- paused: Development work temporarily stopped. Can resume to
or cancel toin_progress
.voided - voided: TC cancelled entirely. Terminal state — cannot transition out.
Commands
/tc init
Initialize TC tracking in the current project. Run this once per project.
Steps:
- Check if
exists. If yes, report "Already initialized" with current stats and stop.docs/TC/tc_config.json - Detect project name: try CLAUDE.md first heading, then package.json name, then pyproject.toml name, then directory basename. Confirm with user.
- Create directories:
,docs/TC/
,docs/TC/records/docs/TC/evidence/ - Create
:tc_config.json{ "project_name": "<detected>", "tc_root": "docs/TC", "created": "<ISO 8601 now>", "skills_library_path": "<absolute path to skills_library/TC>", "auto_track": true, "auto_regenerate_html": true, "auto_regenerate_dashboard": true, "default_author": "Claude", "categories": ["feature","bugfix","refactor","infrastructure","documentation","hotfix","enhancement"] } - Create
:tc_registry.json{ "project_name": "<name>", "created": "<ISO 8601>", "updated": "<ISO 8601>", "next_tc_number": 1, "records": [], "statistics": { "total": 0, "by_status": {"planned":0,"in_progress":0,"blocked":0,"implemented":0,"tested":0,"deployed":0,"paused":0,"voided":0}, "by_scope": {"feature":0,"bugfix":0,"refactor":0,"infrastructure":0,"documentation":0,"hotfix":0,"enhancement":0}, "by_priority": {"critical":0,"high":0,"medium":0,"low":0} } } - Generate empty dashboard: run
python "<skills_path>/generators/generate_dashboard.py" "docs/TC/tc_registry.json" - Update CLAUDE.md: read existing file (or create new). Check for marker
. If not found, append the contents of## Technical Change (TC) Tracking (MANDATORY)
withinit/claude_md_snippet.md
replaced with the actual absolute path.{skills_library_path} - Update
: read existing file (or create.claude/settings.local.json
). Merge TC permissions from{"permissions":{"allow":[]}}
(with paths substituted). Deduplicate. Write back.init/settings_template.json - Report all created/updated files. Suggest
as next step./tc create
/tc create <functionality-name>
Create a new TC record.
Steps:
- Read
docs/TC/tc_registry.json - Generate TC ID:
TC-{next_tc_number:03d}-{MM-DD-YY}-{slugify(name)} - Ask user for:
- Title (default: formatted version of the slug)
- Scope: feature, bugfix, refactor, infrastructure, documentation, hotfix, enhancement
- Priority: critical, high, medium, low (default: medium)
- Summary (at least 10 characters)
- Motivation (why is this change needed?)
- Create directory:
docs/TC/records/TC-NNN-MM-DD-YY-slug/ - Create
with all fields initialized:tc_record.json- status = "planned"
- revision_history = [R1 creation event]
- session_context.current_session populated with this session's info
- All arrays initialized to []
- approval.approved = false, test_coverage_status = "none"
- Add entry to tc_registry.json records array. Increment next_tc_number. Recompute statistics.
- Generate HTML: run the tc_record HTML generator
- Regenerate dashboard: run the dashboard generator
- Report: display TC ID, link to HTML, suggest next steps
/tc update <tc-id>
Update an existing TC record. This is the general-purpose update command.
Steps:
- Read the TC record from
docs/TC/records/<tc-dir>/tc_record.json - Determine what to update (user may specify, or you determine from context):
- Status change: validate transition with state machine. Ask for reason.
- Add files: append to files_affected array
- Add test case: create new test entry with sequential ID (T1, T2...)
- Update test result: set actual_result, status, evidence, tested_by, tested_date
- Add evidence: append to a test case's evidence array
- Update handoff: update session_context.handoff fields
- Add notes: append to notes field
- Add sub-TC: append to sub_tcs array
- For EVERY change:
- Append a new revision entry to revision_history (sequential R-id, timestamp, author, summary, field_changes with old/new values and reason)
- Update the
timestampupdated - Update
andmetadata.last_modifiedmetadata.last_modified_by - Update
session_context.current_session.last_active
- Write tc_record.json (atomic: write to .tmp, then rename)
- Update tc_registry.json (sync status, scope, priority, updated, test_summary). Recompute statistics.
- If auto_regenerate_html: regenerate TC HTML
- If status changed and auto_regenerate_dashboard: regenerate dashboard
/tc status [tc-id]
View TC status.
Without tc-id: Read tc_registry.json and display a summary table of all TCs:
- TC ID, Title, Status (with badge), Scope, Priority, Tests (pass/total), Last Updated
With tc-id: Read the specific TC record and display:
- Full status including handoff data, test results, revision count, files affected
- Any validation errors
/tc resume <tc-id>
Resume work on a TC from a previous session.
Steps:
- Read the TC record
- Display the handoff section prominently:
- Progress summary
- Next steps (numbered)
- Blockers (highlighted)
- Key context
- Files in progress with their states
- Recent decisions
- Archive the current session to session_history:
- Move current_session data to a new entry in session_history
- Set ended = now
- Create new current_session with this session's info
- Append revision entry: "Session resumed by [platform/model]"
- Write tc_record.json
- Prompt: "Ready to continue. Here are the next steps: [list from handoff]"
/tc close <tc-id>
Close a TC by transitioning it to deployed.
Steps:
- Read the TC record
- Validate current status allows transition to
deployed - Check all test cases — warn if any are pending/fail/blocked
- Ask for:
- Approval: who is approving? (user name or "self")
- Approval notes (optional)
- Final test coverage assessment (none/partial/full)
- Update:
- status = "deployed"
- approval.approved = true
- approval.approved_by, approved_date, approval_notes, test_coverage_status
- Append final revision entry
- Archive session to session_history
- Write tc_record.json and update registry
- Regenerate HTML and dashboard
- Report: "TC-NNN closed and deployed."
/tc export
Regenerate ALL HTML files from their JSON records.
Steps:
- Read tc_registry.json
- For each record: run the TC HTML generator on its tc_record.json
- Run the dashboard generator
- Report: "Regenerated X TC pages and dashboard."
/tc dashboard
Regenerate just the dashboard index.html.
Steps:
- Run the dashboard generator on tc_registry.json
- Report path to generated index.html
/tc retro <retro_changelog.json>
Retroactively create TC records in bulk from a structured changelog file. Use this when onboarding an existing project with extensive undocumented history.
Steps:
- Read the retro_changelog.json file (must match
)schemas/tc_retro_changelog.schema.json - Validate the changelog structure
- Run the batch generator:
python "{skills_library_path}/generators/generate_retro_tcs.py" "<retro_changelog.json>" "docs/TC" - The generator will:
- Create a TC record for each entry (TC-001 through TC-NNN)
- Validate every record against the schema
- Generate HTML for every record
- Update the registry with all entries
- Regenerate the dashboard
- Report: total created, any errors, link to dashboard
Retro Changelog Format (
retro_changelog.json):
{ "project": "Project Name", "default_author": "retroactive", "changes": [ { "title": "Feature or Change Title", "scope": "feature|bugfix|refactor|infrastructure|documentation|hotfix|enhancement", "priority": "critical|high|medium|low", "status": "deployed", "date": "YYYY-MM-DD", "description": "What changed and why (10+ chars)", "motivation": "Why this change was needed (optional)", "files": ["path/to/file.py", "path/to/other.py"], "tags": ["tag1", "tag2"], "version": "v1.0.0" } ] }
Building the changelog: Claude should analyze the project's git history, docs, changelogs, README, and code to build the retro_changelog.json. Group related changes into single TCs. Each TC should represent one logical unit of work (a feature, a fix, a refactor).
/tc retro --from-git
Auto-generate the retro_changelog.json directly from git history instead of building it manually.
Steps:
- Run the git-to-changelog generator:
python "{skills_library_path}/generators/generate_retro_from_git.py" \ --repo-path "." \ --output "retro_changelog.json" \ --project-name "Project Name" \ --since "2024-01-01" \ --until "2026-04-05" - The generator will:
- Parse
to extract all commits with files changed, dates, authors, messagesgit log - Group related commits into logical TCs using:
- Merge commit / PR boundaries (primary, if the repo uses merge/squash workflow)
- File-overlap clustering (commits touching the same files)
- Time-proximity grouping (same author, within ~2 hour window)
- Auto-detect scope from commit messages: "fix" -> bugfix, "feat" -> feature, "refactor" -> refactor, "docs" -> documentation, "chore"/"ci" -> infrastructure
- Auto-detect priority: default medium, "critical"/"urgent"/"hotfix" -> critical/high
- Write a valid
matchingretro_changelog.jsonschemas/tc_retro_changelog.schema.json
- Parse
- Review the generated changelog (optional but recommended — edit titles, adjust scopes/priorities)
- Feed it into the batch TC generator:
python "{skills_library_path}/generators/generate_retro_tcs.py" "retro_changelog.json" "docs/TC" - Report: total TCs created, link to dashboard
CLI Options:
| Flag | Default | Description |
|---|---|---|
| | Path to the git repository |
| | Output file path |
| auto-detected | Project name for the changelog header |
| (all history) | Only include commits after YYYY-MM-DD |
| (all history) | Only include commits up to YYYY-MM-DD |
| | Default author field in the changelog |
| | Clustering time window in hours |
/tc link <tc-id> [<sha>|HEAD|--range A..B]
Link git commits to a TC record. Appends to
git.commits[], merges files into files_affected[], adds a revision entry.
Steps:
- Resolve the SHA (default: HEAD). For
, resolve all commits in the range.--range - For each commit: read metadata via
, skip if SHA already linked (dedup).git show - Append to
withgit.commits[]
.link_source: "manual" - Merge
intofiles_changed
(skip duplicates).files_affected[] - Append revision history entry: "Linked N commit(s)".
- Regenerate TC HTML.
/tc git status
Show the git integration state of all TC records.
Output:
- Unlinked TCs: Records with no
block (candidates forgit
)/tc link - Linked TCs: Records with
populated (with commit count)git.commits[] - Online-enriched TCs: Records with PR metadata
- Unlinked commits: Recent commits on the current branch not linked to any TC
- Uncommitted files: Matching
of in-progress TCsfiles_affected[]
/tc pr link <tc-id> [<pr-number>]
(Online opt-in) Link a PR/MR to a TC record. Requires
gh (GitHub) or glab (GitLab) CLI.
Steps:
- Auto-detect provider from
.git remote -v - If no PR number given, find PR for current branch via
.gh pr view <branch> - Populate
with number, URL, state, review decision, merge commit.git.remotes[].pr - Append revision entry. Regenerate TC HTML.
- Graceful degradation: if CLI is missing or unauthenticated, report and exit cleanly.
/tc sync [<tc-id>|--all]
(Online opt-in) Refresh PR metadata for TCs with linked PRs.
Steps:
- For each TC with
populated:git.remotes[].pr.number- Query current PR state via
orgh pr view
.glab mr view - Update state, review_decision, merged_sha, last_synced.
- Query current PR state via
- If PR state changed, append revision entry.
- Report: "Updated N TC(s)" or "No changes (offline or up-to-date)".
/tc git install-merge-driver
Register the TC registry merge driver to handle
tc_registry.json conflicts during rebases and merges.
Steps:
- Run:
git config merge.tc-registry.driver 'python "<path>/tc_registry_merge.py" %O %A %B' - Add to
:.gitattributesdocs/TC/tc_registry.json merge=tc-registry - Report: "Merge driver registered."
Auto-Detection Rules — Non-Blocking Subagent Pattern
TC tracking MUST NOT interrupt the main workflow. Use background subagents for all bookkeeping.
During Work
- NEVER stop to update TC records inline. Focus entirely on the task.
- Do not read/write TC files between code changes.
- The main agent's job is to code, not to do paperwork.
At Natural Milestones
When a logical unit of work is complete (feature done, test passing, stopping point):
- Spawn a background Agent (run_in_background=true) with this prompt: "Read docs/TC/tc_registry.json. Find the in_progress TC. Read its tc_record.json. Update files_affected with [list files changed]. Append a revision entry summarizing what was done. Update session_context.current_session.last_active. Write the updated record. Regenerate the TC HTML and dashboard."
- The main agent continues working without waiting.
Only Surface Questions When Genuinely Needed
- "This work doesn't match any active TC — should I create one?" (ask once per session, not per file)
- "TC-NNN looks complete — transition to implemented?" (at milestones only, don't nag)
- Never interrupt the user for routine TC bookkeeping.
At Session End
Before the session closes, spawn a final background Agent to write the handoff summary:
- progress_summary: what was accomplished
- next_steps: what still needs doing
- blockers: anything preventing progress
- key_context: important decisions, gotchas, patterns the next bot needs
- files_in_progress: which files are mid-edit
On Session Start
- Check if
exists in the projectdocs/TC/ - If yes: read tc_registry.json, find in_progress/blocked TCs
- Display handoff summary for any active TCs
- Ask user if they want to resume
Validation Rules (Always Enforced)
- State machine: only valid transitions allowed (see diagram above)
- Sequential IDs: revision_history uses R1,R2,R3...; test_cases uses T1,T2,T3...
- Append-only history: revision_history entries are never modified or deleted
- Approval consistency: approved=true requires approved_by and approved_date
- TC ID format: must match
patternTC-NNN-MM-DD-YY-slug - Sub-TC ID format: must match
orTC-NNN.A
patternTC-NNN.A.N - HTML escaping: all user data is escaped before HTML rendering
- Atomic writes: JSON files written to .tmp then renamed
- Registry stats: recomputed on every registry write
Python Generators
Located at
{skills_library_path}/generators/:
# Generate individual TC HTML python "generators/generate_tc_html.py" "<path_to_tc_record.json>" [--output <path>] # Generate dashboard python "generators/generate_dashboard.py" "<path_to_tc_registry.json>" [--output <path>] # Validate a TC record python "validators/validate_tc.py" "<path_to_tc_record.json>" # Validate the registry python "validators/validate_tc.py" --registry "<path_to_tc_registry.json>" # Retroactive batch creation python "generators/generate_retro_tcs.py" "<retro_changelog.json>" "<docs/TC/>" # Generate retro_changelog.json from git history python "generators/generate_retro_from_git.py" [--repo-path .] [--output retro_changelog.json] [--project-name "Name"] [--since 2024-01-01] [--until 2026-04-05] # --- Git Integration --- # Link commit(s) to a TC record python "generators/tc_git_link.py" "<tc_record.json>" [<sha>|HEAD] [--range A..B] # Show git integration status for all TCs (finds unlinked TCs + unlinked commits) python "generators/tc_git_status.py" "<docs/TC/>" [--unlinked-only] [--show-candidates] # Auto-link HEAD to the single in-progress TC (used by PostToolUse hook) python "generators/tc_git_autolink.py" --if-commit [<docs/TC/>] # Pre-commit advisory: warn if staged files aren't in any active TC (used by PreToolUse hook) python "generators/tc_precommit_check.py" --if-commit [<docs/TC/>] # Registry 3-way merge driver (register with git config for conflict resolution) python "generators/tc_registry_merge.py" <base> <ours> <theirs> # --- Online (opt-in) --- # Link a PR/MR to a TC record (requires gh or glab CLI) python "generators/tc_pr_link.py" "<tc_record.json>" [<pr_number>] # Refresh PR metadata for all TCs with linked PRs python "generators/tc_sync.py" "<docs/TC/>" [<tc_id>] # --- Session Lifecycle --- # Display session start report with active TC handoff data python "generators/tc_session_start.py" "<docs/TC/>" [--json] # Archive current session and write handoff data python "generators/tc_session_end.py" "<tc_record.json>" [--summary "..."] [--next "..."]
All generators use Python stdlib only — no external dependencies. All generators validate their input before producing output. All HTML output is self-contained with inlined CSS (works from file:// URLs). All HTML output is WCAG AA+ accessible with rem-based fonts, high contrast dark theme, skip links, and aria labels.