@ikon85/agent-workflow-kit 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/ask-matt/SKILL.md +139 -0
- package/.agents/skills/ask-matt/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/audit-skills/SKILL.md +145 -0
- package/.agents/skills/board-to-waves/SKILL.md +135 -0
- package/.agents/skills/code-review/SKILL.md +64 -0
- package/.agents/skills/codebase-design/DEEPENING.md +37 -0
- package/.agents/skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
- package/.agents/skills/codebase-design/SKILL.md +114 -0
- package/.agents/skills/codebase-design/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/codex-adapter-sync/SKILL.md +151 -0
- package/.agents/skills/decision-gate/SKILL.md +67 -0
- package/.agents/skills/diagnose/SKILL.md +136 -0
- package/.agents/skills/diagnose/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/diagnose/scripts/hitl-loop.template.sh +41 -0
- package/.agents/skills/domain-modeling/ADR-FORMAT.md +47 -0
- package/.agents/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
- package/.agents/skills/domain-modeling/SKILL.md +76 -0
- package/.agents/skills/domain-modeling/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/git-worktree-recover/SKILL.md +176 -0
- package/.agents/skills/grill-me/SKILL.md +54 -0
- package/.agents/skills/grill-me/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/grill-with-docs/ADR-FORMAT.md +47 -0
- package/.agents/skills/grill-with-docs/CONTEXT-FORMAT.md +60 -0
- package/.agents/skills/grill-with-docs/SKILL.md +137 -0
- package/.agents/skills/grill-with-docs/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/implement/SKILL.md +15 -0
- package/.agents/skills/implement/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/improve-codebase-architecture/ADR-FORMAT.md +47 -0
- package/.agents/skills/improve-codebase-architecture/CONTEXT-FORMAT.md +60 -0
- package/.agents/skills/improve-codebase-architecture/DEEPENING.md +37 -0
- package/.agents/skills/improve-codebase-architecture/HTML-REPORT.md +123 -0
- package/.agents/skills/improve-codebase-architecture/INTERFACE-DESIGN.md +46 -0
- package/.agents/skills/improve-codebase-architecture/LANGUAGE.md +53 -0
- package/.agents/skills/improve-codebase-architecture/SKILL.md +88 -0
- package/.agents/skills/improve-codebase-architecture/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/kit-release/SKILL.md +56 -0
- package/.agents/skills/local-ci/SKILL.md +94 -0
- package/.agents/skills/orchestrate-wave/SKILL.md +261 -0
- package/.agents/skills/orchestrate-wave/references/builder-contract.md +67 -0
- package/.agents/skills/prototype/LOGIC.md +79 -0
- package/.agents/skills/prototype/SKILL.md +30 -0
- package/.agents/skills/prototype/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/prototype/UI.md +112 -0
- package/.agents/skills/research/SKILL.md +12 -0
- package/.agents/skills/research/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/resolving-merge-conflicts/SKILL.md +14 -0
- package/.agents/skills/resolving-merge-conflicts/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/retro/SKILL.md +209 -0
- package/.agents/skills/scale-check/SKILL.md +141 -0
- package/.agents/skills/security-audit/SKILL.md +67 -0
- package/.agents/skills/setup-workflow/SKILL.md +187 -0
- package/.agents/skills/setup-workflow/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/setup-workflow/board-sync.md +111 -0
- package/.agents/skills/setup-workflow/code-review.md +26 -0
- package/.agents/skills/setup-workflow/domain.md +51 -0
- package/.agents/skills/setup-workflow/issue-tracker-github.md +35 -0
- package/.agents/skills/setup-workflow/issue-tracker-gitlab.md +34 -0
- package/.agents/skills/setup-workflow/issue-tracker-local.md +30 -0
- package/.agents/skills/setup-workflow/orchestrate-wave-seed.md +44 -0
- package/.agents/skills/setup-workflow/spec-completeness-seed.md +44 -0
- package/.agents/skills/setup-workflow/spec-self-critique-seed.md +43 -0
- package/.agents/skills/setup-workflow/triage-labels.md +18 -0
- package/.agents/skills/setup-workflow/workflow-overview.md +33 -0
- package/.agents/skills/spec-self-critique/SKILL.md +152 -0
- package/.agents/skills/spec-self-critique/scenarios.md +82 -0
- package/.agents/skills/tdd/SKILL.md +120 -0
- package/.agents/skills/tdd/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/tdd/deep-modules.md +33 -0
- package/.agents/skills/tdd/interface-design.md +31 -0
- package/.agents/skills/tdd/mocking.md +59 -0
- package/.agents/skills/tdd/refactoring.md +10 -0
- package/.agents/skills/tdd/tests.md +61 -0
- package/.agents/skills/to-issues/SKILL.md +325 -0
- package/.agents/skills/to-issues/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/to-prd/PROGRAM-PRD-FORMAT.md +162 -0
- package/.agents/skills/to-prd/SKILL.md +180 -0
- package/.agents/skills/to-prd/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/to-waves/SKILL.md +260 -0
- package/.agents/skills/to-waves/SLICE-METADATA-FORMAT.md +74 -0
- package/.agents/skills/triage/AGENT-BRIEF.md +168 -0
- package/.agents/skills/triage/OUT-OF-SCOPE.md +101 -0
- package/.agents/skills/triage/SKILL.md +122 -0
- package/.agents/skills/triage/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/verify-spike/SKILL.md +39 -0
- package/.agents/skills/wayfinder/SKILL.md +127 -0
- package/.agents/skills/wayfinder/THIRD-PARTY-NOTICES.md +29 -0
- package/.agents/skills/wrapup/SKILL.md +71 -0
- package/.agents/skills/wrapup/SOURCES.txt +6 -0
- package/.agents/skills/zoom-out/SKILL.md +7 -0
- package/.agents/skills/zoom-out/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/hooks/_hook_utils.py +184 -0
- package/.claude/hooks/drift-guard.py +176 -0
- package/.claude/hooks/skill-drift-hint.py +122 -0
- package/.claude/hooks/sync-board-status.py +191 -0
- package/.claude/skills/ask-matt/SKILL.md +139 -0
- package/.claude/skills/ask-matt/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/audit-skills/SKILL.md +145 -0
- package/.claude/skills/board-to-waves/SKILL.md +148 -0
- package/.claude/skills/code-review/SKILL.md +64 -0
- package/.claude/skills/codebase-design/DEEPENING.md +37 -0
- package/.claude/skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
- package/.claude/skills/codebase-design/SKILL.md +114 -0
- package/.claude/skills/codebase-design/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/codex-build/SKILL.md +126 -0
- package/.claude/skills/codex-build/THIRD-PARTY-NOTICES.md +35 -0
- package/.claude/skills/codex-review/SKILL.md +145 -0
- package/.claude/skills/codex-review/THIRD-PARTY-NOTICES.md +31 -0
- package/.claude/skills/decision-gate/SKILL.md +67 -0
- package/.claude/skills/diagnose/SKILL.md +136 -0
- package/.claude/skills/diagnose/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/diagnose/scripts/hitl-loop.template.sh +41 -0
- package/.claude/skills/domain-modeling/ADR-FORMAT.md +47 -0
- package/.claude/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
- package/.claude/skills/domain-modeling/SKILL.md +76 -0
- package/.claude/skills/domain-modeling/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/git-guardrails-claude-code/SKILL.md +96 -0
- package/.claude/skills/git-guardrails-claude-code/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/git-guardrails-claude-code/scripts/block-dangerous-git.sh +28 -0
- package/.claude/skills/git-worktree-recover/SKILL.md +182 -0
- package/.claude/skills/grill-me/SKILL.md +54 -0
- package/.claude/skills/grill-me/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/grill-me-codex/SKILL.md +158 -0
- package/.claude/skills/grill-me-codex/THIRD-PARTY-NOTICES.md +32 -0
- package/.claude/skills/grill-with-docs/ADR-FORMAT.md +47 -0
- package/.claude/skills/grill-with-docs/CONTEXT-FORMAT.md +60 -0
- package/.claude/skills/grill-with-docs/SKILL.md +137 -0
- package/.claude/skills/grill-with-docs/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/grill-with-docs-codex/ADR-FORMAT.md +47 -0
- package/.claude/skills/grill-with-docs-codex/CONTEXT-FORMAT.md +60 -0
- package/.claude/skills/grill-with-docs-codex/SKILL.md +233 -0
- package/.claude/skills/grill-with-docs-codex/THIRD-PARTY-NOTICES.md +33 -0
- package/.claude/skills/implement/SKILL.md +15 -0
- package/.claude/skills/implement/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/improve-codebase-architecture/ADR-FORMAT.md +47 -0
- package/.claude/skills/improve-codebase-architecture/CONTEXT-FORMAT.md +60 -0
- package/.claude/skills/improve-codebase-architecture/DEEPENING.md +37 -0
- package/.claude/skills/improve-codebase-architecture/HTML-REPORT.md +123 -0
- package/.claude/skills/improve-codebase-architecture/INTERFACE-DESIGN.md +46 -0
- package/.claude/skills/improve-codebase-architecture/LANGUAGE.md +53 -0
- package/.claude/skills/improve-codebase-architecture/SKILL.md +88 -0
- package/.claude/skills/improve-codebase-architecture/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/kit-release/SKILL.md +56 -0
- package/.claude/skills/local-ci/SKILL.md +94 -0
- package/.claude/skills/orchestrate-wave/SKILL.md +269 -0
- package/.claude/skills/orchestrate-wave/references/builder-contract.md +67 -0
- package/.claude/skills/prototype/LOGIC.md +79 -0
- package/.claude/skills/prototype/SKILL.md +30 -0
- package/.claude/skills/prototype/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/prototype/UI.md +112 -0
- package/.claude/skills/research/SKILL.md +12 -0
- package/.claude/skills/research/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/resolving-merge-conflicts/SKILL.md +14 -0
- package/.claude/skills/resolving-merge-conflicts/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/retro/SKILL.md +209 -0
- package/.claude/skills/scale-check/SKILL.md +141 -0
- package/.claude/skills/security-audit/SKILL.md +67 -0
- package/.claude/skills/setup-pre-commit/SKILL.md +104 -0
- package/.claude/skills/setup-pre-commit/scripts/pre-commit.template.sh +35 -0
- package/.claude/skills/setup-workflow/SKILL.md +187 -0
- package/.claude/skills/setup-workflow/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/setup-workflow/board-sync.md +111 -0
- package/.claude/skills/setup-workflow/code-review.md +26 -0
- package/.claude/skills/setup-workflow/domain.md +51 -0
- package/.claude/skills/setup-workflow/issue-tracker-github.md +35 -0
- package/.claude/skills/setup-workflow/issue-tracker-gitlab.md +34 -0
- package/.claude/skills/setup-workflow/issue-tracker-local.md +30 -0
- package/.claude/skills/setup-workflow/orchestrate-wave-seed.md +44 -0
- package/.claude/skills/setup-workflow/spec-completeness-seed.md +44 -0
- package/.claude/skills/setup-workflow/spec-self-critique-seed.md +43 -0
- package/.claude/skills/setup-workflow/triage-labels.md +18 -0
- package/.claude/skills/setup-workflow/workflow-overview.md +33 -0
- package/.claude/skills/skill-manifest.json +389 -0
- package/.claude/skills/spec-self-critique/SKILL.md +152 -0
- package/.claude/skills/spec-self-critique/scenarios.md +82 -0
- package/.claude/skills/tdd/SKILL.md +120 -0
- package/.claude/skills/tdd/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/tdd/deep-modules.md +33 -0
- package/.claude/skills/tdd/interface-design.md +31 -0
- package/.claude/skills/tdd/mocking.md +59 -0
- package/.claude/skills/tdd/refactoring.md +10 -0
- package/.claude/skills/tdd/tests.md +61 -0
- package/.claude/skills/to-issues/SKILL.md +325 -0
- package/.claude/skills/to-issues/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/to-prd/PROGRAM-PRD-FORMAT.md +162 -0
- package/.claude/skills/to-prd/SKILL.md +180 -0
- package/.claude/skills/to-prd/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/to-waves/SKILL.md +260 -0
- package/.claude/skills/to-waves/SLICE-METADATA-FORMAT.md +74 -0
- package/.claude/skills/triage/AGENT-BRIEF.md +168 -0
- package/.claude/skills/triage/OUT-OF-SCOPE.md +101 -0
- package/.claude/skills/triage/SKILL.md +122 -0
- package/.claude/skills/triage/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/verify-spike/SKILL.md +39 -0
- package/.claude/skills/wayfinder/SKILL.md +127 -0
- package/.claude/skills/wayfinder/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/wrapup/SKILL.md +81 -0
- package/.claude/skills/wrapup/SOURCES.txt +6 -0
- package/.claude/skills/write-a-skill/GLOSSARY.md +201 -0
- package/.claude/skills/write-a-skill/SKILL.md +88 -0
- package/.claude/skills/write-a-skill/THIRD-PARTY-NOTICES.md +29 -0
- package/.claude/skills/zoom-out/SKILL.md +7 -0
- package/.claude/skills/zoom-out/THIRD-PARTY-NOTICES.md +29 -0
- package/LICENSE +28 -0
- package/PROVENANCE.md +39 -0
- package/README.md +619 -0
- package/agent-workflow-kit.package.json +1939 -0
- package/docs/agents/board-sync.md +71 -0
- package/docs/agents/code-review.md +14 -0
- package/docs/agents/domain.md +7 -0
- package/docs/agents/issue-tracker.md +12 -0
- package/docs/agents/security-audit-runbook-template.md +205 -0
- package/docs/agents/skills/orchestrate-wave.md +13 -0
- package/docs/agents/skills/spec-self-critique.md +18 -0
- package/docs/agents/triage-labels.md +10 -0
- package/docs/agents/wave-anchor-template.md +88 -0
- package/docs/conventions/spec-completeness.md +23 -0
- package/docs/index.html +56 -0
- package/docs/methodology.html +488 -0
- package/docs/methodology.svg +93 -0
- package/docs/workflow.png +0 -0
- package/package.json +40 -0
- package/scripts/anchor_table.py +343 -0
- package/scripts/board-sync.py +1232 -0
- package/scripts/board_config.py +147 -0
- package/scripts/board_fields.py +192 -0
- package/scripts/build-kit.mjs +116 -0
- package/scripts/build-kit.test.mjs +59 -0
- package/scripts/check-kit-staleness.mjs +45 -0
- package/scripts/check-kit-staleness.test.mjs +19 -0
- package/scripts/execute-ready-check.py +516 -0
- package/scripts/issue_deps.py +79 -0
- package/scripts/kit-release.mjs +100 -0
- package/scripts/kit-release.test.mjs +67 -0
- package/scripts/lib/audit-refs.mjs +146 -0
- package/scripts/lib/scrub.mjs +113 -0
- package/scripts/lib/scrub.test.mjs +187 -0
- package/scripts/loc_offender_core.py +196 -0
- package/scripts/loc_offender_gate.py +182 -0
- package/scripts/node_kind.py +68 -0
- package/scripts/portability_profile_scan.py +53 -0
- package/scripts/pr-body-check.py +263 -0
- package/scripts/program_graph.py +125 -0
- package/scripts/program_graph_parse.py +275 -0
- package/scripts/program_graph_validate.py +256 -0
- package/scripts/program_sync.py +160 -0
- package/scripts/release-delta-guard.mjs +96 -0
- package/scripts/release-delta-guard.test.mjs +53 -0
- package/scripts/test_board_sync_create_idempotency.py +104 -0
- package/scripts/test_dist_kit_smoke.py +199 -0
- package/scripts/test_kit_docs_language_census.py +178 -0
- package/scripts/test_skill_code_review_seed.py +89 -0
- package/scripts/test_skill_frontmatter_lint.py +226 -0
- package/scripts/test_skill_gh_lint.py +124 -0
- package/scripts/test_skill_language_census.py +254 -0
- package/scripts/test_skill_portability_lint.py +773 -0
- package/scripts/test_skill_publish_audit.py +300 -0
- package/scripts/test_skill_selfcontainment_lint.py +255 -0
- package/scripts/test_skill_setup_workflow_seeds.py +200 -0
- package/scripts/test_skill_stale_name_lint.py +126 -0
- package/scripts/test_skill_surface_refs.py +300 -0
- package/scripts/test_skill_trailing_artifact_lint.py +71 -0
- package/scripts/wrapup-land.py +573 -0
- package/src/cli.mjs +70 -0
- package/src/commands/diff.mjs +6 -0
- package/src/commands/init.mjs +59 -0
- package/src/commands/uninstall.mjs +43 -0
- package/src/commands/update.mjs +95 -0
- package/src/lib/atomicWrite.mjs +49 -0
- package/src/lib/bundle.mjs +133 -0
- package/src/lib/hash.mjs +13 -0
- package/src/lib/manifest.mjs +58 -0
- package/src/lib/sentinel.mjs +20 -0
- package/src/lib/settings.mjs +23 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Sync GitHub Project status to the in-progress status when the current branch is
|
|
4
|
+
feat/<#>- or fix/<#>-.
|
|
5
|
+
|
|
6
|
+
Wired as SessionStart hook. Idempotent + scoped:
|
|
7
|
+
- only the project + status field named in the board profile
|
|
8
|
+
- only transitions {idea, triaged, spec} roles -> inProgress role (whitelist,
|
|
9
|
+
names resolved via the profile's fields.status.roles map —)
|
|
10
|
+
- silent on every failure (never blocks session start)
|
|
11
|
+
|
|
12
|
+
Board-specific values (project ids, status option ids, repo slug) are NOT
|
|
13
|
+
inlined — they are read from the board profile (docs/agents/board-sync.md, parsed
|
|
14
|
+
by scripts/board_config.py, /setup-workflow-seeded per repo). So this hook works
|
|
15
|
+
unchanged in this repo and in a consumer install alike.
|
|
16
|
+
|
|
17
|
+
Lookup is TARGETED: it queries ONLY the active issue's project items (GraphQL
|
|
18
|
+
issue.projectItems), not the whole board. So it has no pagination cap (the old
|
|
19
|
+
`item-list --limit 500` silently dropped the newest issues on large boards) and
|
|
20
|
+
ignores every Done/closed/archived item elsewhere — those are never a transition
|
|
21
|
+
source, so reading them was pure noise.
|
|
22
|
+
|
|
23
|
+
Audit log: .claude/logs/board-sync.log
|
|
24
|
+
"""
|
|
25
|
+
import argparse
|
|
26
|
+
import json
|
|
27
|
+
import re
|
|
28
|
+
import sys
|
|
29
|
+
from pathlib import Path
|
|
30
|
+
|
|
31
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
32
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent / "scripts"))
|
|
33
|
+
from _hook_utils import log, run_with_status as run # noqa: E402
|
|
34
|
+
from board_config import load_board_config, status_roles, ConfigError # noqa: E402
|
|
35
|
+
|
|
36
|
+
# The transition is derived from the profile's semantic role map — the hook
|
|
37
|
+
# carries role KEYS (schema), never status-name vocabulary.
|
|
38
|
+
_FROM_ROLES = ("idea", "triaged", "spec")
|
|
39
|
+
_TARGET_ROLE = "inProgress"
|
|
40
|
+
BRANCH_RE = re.compile(r"^(?:feat|fix)/([0-9]+)-")
|
|
41
|
+
HOOK_NAME = "board-sync"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def derive_transition(roles):
|
|
45
|
+
"""(allowed_from_names, target_name) derived from the profile's
|
|
46
|
+
`fields.status.roles` map, or (None, reason) when the inProgress role is
|
|
47
|
+
unconfigured (old profile without the map → visible skip, never a crash).
|
|
48
|
+
Missing from-roles are tolerated — a board without an idea-like stage
|
|
49
|
+
simply has a smaller whitelist."""
|
|
50
|
+
target = roles.get(_TARGET_ROLE)
|
|
51
|
+
if not target:
|
|
52
|
+
return None, ("status role 'inProgress' not configured — add "
|
|
53
|
+
"fields.status.roles to the board profile (see "
|
|
54
|
+
"docs/agents/board-sync.md)")
|
|
55
|
+
allowed = {roles[r] for r in _FROM_ROLES if roles.get(r)}
|
|
56
|
+
return allowed, target
|
|
57
|
+
|
|
58
|
+
# Fetch one issue's project items + their single-select field values. Matching
|
|
59
|
+
# the status by FIELD ID (not the display name "Status") keeps it profile-driven.
|
|
60
|
+
_ITEM_QUERY = (
|
|
61
|
+
"query($owner:String!,$repo:String!,$number:Int!){"
|
|
62
|
+
"repository(owner:$owner,name:$repo){issue(number:$number){"
|
|
63
|
+
"projectItems(first:20){nodes{id project{number} "
|
|
64
|
+
"fieldValues(first:20){nodes{"
|
|
65
|
+
"... on ProjectV2ItemFieldSingleSelectValue{name "
|
|
66
|
+
"field{... on ProjectV2SingleSelectField{id}}}"
|
|
67
|
+
"}}}}}}}"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def resolve_status_from_items(issue, proj_number, field_id):
|
|
72
|
+
"""Pure decision core: given the already-parsed `data.repository.issue`
|
|
73
|
+
node from the board-item GraphQL response, disambiguate this issue's item
|
|
74
|
+
in `proj_number` and extract its value for `field_id`.
|
|
75
|
+
|
|
76
|
+
No subprocess/network — parsed dict in, decision out. Returns
|
|
77
|
+
(item_id, current_status) on a clean single-item match (current is ""
|
|
78
|
+
when the field has never been set), or (None, reason) on any miss:
|
|
79
|
+
issue not found, 0/2+ project items in the target project (incl. items
|
|
80
|
+
that belong to a *different* project number), or a malformed item id.
|
|
81
|
+
"""
|
|
82
|
+
if not issue:
|
|
83
|
+
return None, "issue not found"
|
|
84
|
+
|
|
85
|
+
nodes = (issue.get("projectItems") or {}).get("nodes") or []
|
|
86
|
+
ours = [n for n in nodes if str((n.get("project") or {}).get("number")) == proj_number]
|
|
87
|
+
if len(ours) != 1:
|
|
88
|
+
return None, f"{len(ours)} project items in project {proj_number}"
|
|
89
|
+
|
|
90
|
+
item_id = ours[0].get("id")
|
|
91
|
+
if not isinstance(item_id, str) or not item_id.startswith("PVTI_"):
|
|
92
|
+
return None, "item id missing or malformed"
|
|
93
|
+
|
|
94
|
+
current = ""
|
|
95
|
+
for fv in (ours[0].get("fieldValues") or {}).get("nodes") or []:
|
|
96
|
+
if (fv.get("field") or {}).get("id") == field_id:
|
|
97
|
+
current = fv.get("name", "")
|
|
98
|
+
break
|
|
99
|
+
return item_id, current
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def fetch_board_item(repo_owner, repo_name, proj_number, field_id, issue_num):
|
|
103
|
+
"""(item_id, current_status) for issue_num's item in the project, or
|
|
104
|
+
(None, reason) on any miss. Reads only this issue's items — no board-wide
|
|
105
|
+
list, no pagination cap, blind to Done/archived items elsewhere."""
|
|
106
|
+
rc, out = run([
|
|
107
|
+
"gh", "api", "graphql",
|
|
108
|
+
"-f", f"query={_ITEM_QUERY}",
|
|
109
|
+
"-F", f"owner={repo_owner}",
|
|
110
|
+
"-F", f"repo={repo_name}",
|
|
111
|
+
"-F", f"number={issue_num}",
|
|
112
|
+
])
|
|
113
|
+
if rc != 0 or not out:
|
|
114
|
+
return None, "gh graphql failed"
|
|
115
|
+
try:
|
|
116
|
+
issue = json.loads(out)["data"]["repository"]["issue"]
|
|
117
|
+
except (json.JSONDecodeError, KeyError, TypeError):
|
|
118
|
+
return None, "invalid graphql response"
|
|
119
|
+
return resolve_status_from_items(issue, proj_number, field_id)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def main() -> int:
|
|
123
|
+
parser = argparse.ArgumentParser()
|
|
124
|
+
parser.add_argument("--dry-run", action="store_true", help="Log intended action without writing")
|
|
125
|
+
parser.add_argument("--issue", help="Override issue # (else parsed from current branch)")
|
|
126
|
+
args = parser.parse_args()
|
|
127
|
+
|
|
128
|
+
try:
|
|
129
|
+
cfg = load_board_config()
|
|
130
|
+
except ConfigError as e:
|
|
131
|
+
log(HOOK_NAME, f"skip: board profile unavailable ({e})")
|
|
132
|
+
return 0
|
|
133
|
+
repo_owner, repo_name = cfg["repo"].split("/", 1)
|
|
134
|
+
proj_number = str(cfg["project"]["number"])
|
|
135
|
+
node_id = cfg["project"]["nodeId"]
|
|
136
|
+
field_id = cfg["fields"]["status"]["id"]
|
|
137
|
+
allowed_from, target_status = derive_transition(status_roles(cfg))
|
|
138
|
+
if allowed_from is None:
|
|
139
|
+
log(HOOK_NAME, f"skip: {target_status}")
|
|
140
|
+
return 0
|
|
141
|
+
target_id = cfg["fields"]["status"]["options"].get(target_status)
|
|
142
|
+
if not target_id:
|
|
143
|
+
log(HOOK_NAME, f"skip: status {target_status!r} (role 'inProgress') not in board profile options")
|
|
144
|
+
return 0
|
|
145
|
+
|
|
146
|
+
if args.issue:
|
|
147
|
+
issue_num = args.issue
|
|
148
|
+
branch = f"(override --issue {issue_num})"
|
|
149
|
+
else:
|
|
150
|
+
rc, branch_out = run(["git", "branch", "--show-current"])
|
|
151
|
+
branch = branch_out.strip()
|
|
152
|
+
if rc != 0 or not branch:
|
|
153
|
+
return 0
|
|
154
|
+
m = BRANCH_RE.match(branch)
|
|
155
|
+
if not m:
|
|
156
|
+
return 0
|
|
157
|
+
issue_num = m.group(1)
|
|
158
|
+
|
|
159
|
+
item_id, current = fetch_board_item(repo_owner, repo_name, proj_number, field_id, issue_num)
|
|
160
|
+
if item_id is None:
|
|
161
|
+
log(HOOK_NAME, f"branch={branch} issue={issue_num} skip: {current}")
|
|
162
|
+
return 0
|
|
163
|
+
|
|
164
|
+
if current not in allowed_from:
|
|
165
|
+
log(HOOK_NAME, f"branch={branch} issue={issue_num} item={item_id} status={current} skip: not in whitelist")
|
|
166
|
+
return 0
|
|
167
|
+
|
|
168
|
+
if args.dry_run:
|
|
169
|
+
log(HOOK_NAME, f"branch={branch} issue={issue_num} item={item_id} before={current} DRY-RUN would set {target_status!r}")
|
|
170
|
+
return 0
|
|
171
|
+
|
|
172
|
+
rc, _ = run([
|
|
173
|
+
"gh", "project", "item-edit",
|
|
174
|
+
"--id", item_id,
|
|
175
|
+
"--project-id", node_id,
|
|
176
|
+
"--field-id", field_id,
|
|
177
|
+
"--single-select-option-id", target_id,
|
|
178
|
+
])
|
|
179
|
+
if rc == 0:
|
|
180
|
+
log(HOOK_NAME, f"branch={branch} issue={issue_num} item={item_id} before={current} after={target_status}")
|
|
181
|
+
else:
|
|
182
|
+
log(HOOK_NAME, f"branch={branch} issue={issue_num} item={item_id} before={current} ERROR: item-edit failed")
|
|
183
|
+
return 0
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
if __name__ == "__main__":
|
|
187
|
+
try:
|
|
188
|
+
sys.exit(main())
|
|
189
|
+
except Exception as e:
|
|
190
|
+
log(HOOK_NAME, f"unexpected error: {e}")
|
|
191
|
+
sys.exit(0)
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ask-matt
|
|
3
|
+
description: Ask which skill or flow fits your situation. A router over the skills in this repo.
|
|
4
|
+
disable-model-invocation: true
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Ask Matt
|
|
8
|
+
|
|
9
|
+
> **Homage + Router.** Adopted from Matt Pocock's `ask-matt` (MIT, github.com/mattpocock/skills @ `7a83a3a`) — the name stays as a nod to upstream, the content is adapted to *this* repo's skill set (the plan→execute→land→learn line plus our gates, cross-model review, and land/learn skills). Provenance: `docs/agents/provenance.md`. Folder↔upstream-name note: `/diagnose` = upstream `diagnosing-bugs`, `/write-a-skill` = upstream `writing-great-skills` (renamed upstream, local names kept).
|
|
10
|
+
|
|
11
|
+
You don't remember every skill, so ask.
|
|
12
|
+
|
|
13
|
+
A **flow** is a path through the skills. Most paths run along one **main flow**; on-ramps and gates merge onto it. Everything else is standalone, or a vocabulary layer that runs underneath.
|
|
14
|
+
|
|
15
|
+
## The main flow: idea → ship
|
|
16
|
+
|
|
17
|
+
The route most work travels. You have an idea and want it built.
|
|
18
|
+
|
|
19
|
+
0. **Size unclear? `/scale-check` first.** A new undertaking without a clear
|
|
20
|
+
size — a new app, a big cross-cutting change, a genuine "where do I even
|
|
21
|
+
start?" — runs `/scale-check` before anything else: a short plain-language
|
|
22
|
+
dialog that routes it to a Program, a Feature, a Direct-Slice, or a Bug,
|
|
23
|
+
and hands back a paste-ready start prompt for the chosen route. **Rule: a
|
|
24
|
+
new build without a clear size runs `scale-check` first** — never guess
|
|
25
|
+
the altitude and jump straight into step 1. Skip this step outright when
|
|
26
|
+
the size is already obvious (a one-line fix, a known bug) — go straight to
|
|
27
|
+
the entry that fits.
|
|
28
|
+
<!-- mirror-xform:start codex-escalation -->
|
|
29
|
+
1. **`/grill-with-docs`** — sharpen the idea by relentless interview. Start here when you **have a codebase**: it's stateful, retaining what it learns in `CONTEXT.md` and ADRs. (No codebase? Use `/grill-me` — see Standalone.) For high-stakes/hard-to-reverse work, add the cross-model variant **`/grill-with-docs-codex`** (see Cross-model review).
|
|
30
|
+
<!-- mirror-xform:end -->
|
|
31
|
+
2. **Branch — can you settle every question in conversation?** If a question needs a runnable answer (state, business logic, a UI you have to see), detour through a prototype, bridged by **`/handoff`** in both directions (see Crossing sessions): `/handoff` out → fresh session → **`/prototype`** to answer with throwaway code → `/handoff` back what you learned.
|
|
32
|
+
3. **Gate — does a slice hinge on an unknown?** Clear it *before* building (see Gate-before-build): a binary fact → **`/verify-spike`**; a bounded "which option" trade-off → **`/decision-gate`**.
|
|
33
|
+
4. **Branch — is this a multi-session build?**
|
|
34
|
+
- **Yes** → **`/to-prd`** (turn the thread into a PRD) → **`/to-issues`** (split into independently-grabbable issues / a wave anchor). Clear context between issues: fresh session per issue, kick off **`/implement`** with the PRD + the single issue.
|
|
35
|
+
- **No** → **`/implement`** right here, same context window.
|
|
36
|
+
|
|
37
|
+
Either way, **`/implement`** builds each issue by driving **`/tdd`** internally — one red-green slice at a time — then closes out with **`/code-review`** (the two-axis Standards×Spec review; project layer at `docs/agents/code-review.md`, seeded by `/setup-workflow`) before committing. Reach for **`/tdd`** on its own to build a concrete behaviour test-first without a full spec, and **`/code-review`** on its own to review any branch/PR against a fixed point.
|
|
38
|
+
5. **Land** → **`/wrapup`** (see Land). **Learn** → **`/retro`** (see Learn).
|
|
39
|
+
|
|
40
|
+
### Context hygiene
|
|
41
|
+
|
|
42
|
+
Keep steps 1–4 in **one unbroken context window** — don't compact or clear until after `/to-issues` — so grilling, PRD, and issues build on the same thinking. Each `/implement` then starts fresh from the issue. If a session gets large before `/to-issues`, don't push on degraded — `/handoff` and continue fresh.
|
|
43
|
+
|
|
44
|
+
## Depth Ladder
|
|
45
|
+
|
|
46
|
+
Prefer the smallest depth that produces a clear next action.
|
|
47
|
+
|
|
48
|
+
- **Program:** the size is genuinely unclear — a new app, a big cross-cutting
|
|
49
|
+
undertaking, several independently-shippable stages. Run `/scale-check`
|
|
50
|
+
first (it owns the altitude criteria catalog — this router only names it);
|
|
51
|
+
two or more criteria tripped routes to a program grill → `/to-prd` →
|
|
52
|
+
`/to-waves`.
|
|
53
|
+
- **Deep:** `/grill-with-docs` followed by `/to-prd` and `/to-issues` when
|
|
54
|
+
terminology, contracts, rollout order, or ownership are still uncertain.
|
|
55
|
+
- **Medium:** `/to-issues` for a ready artefact that needs slicing.
|
|
56
|
+
- **Light:** direct `/tdd` for a small, well-understood change.
|
|
57
|
+
- **Gate:** insert `/verify-spike` or `/decision-gate` before any depth level
|
|
58
|
+
when a slice hinges on an unresolved fact or trade-off.
|
|
59
|
+
|
|
60
|
+
## Gate-before-build
|
|
61
|
+
|
|
62
|
+
When `/to-issues` cuts a slice that hinges on an unknown, it tags the slice instead of guessing. The gate is its own slice, sequenced *before* the build slice it blocks.
|
|
63
|
+
|
|
64
|
+
- **`/verify-spike`** — a single yes/no fact against the real lib/runtime/DB/platform, answered by a throwaway read-only harness with output-proof.
|
|
65
|
+
- **`/decision-gate`** — a bounded trade-off ("which option") or a targeted research gap: options × criteria table + reasoned pick, sunk to an ADR/issue.
|
|
66
|
+
<!-- mirror-xform:start codex-escalation -->
|
|
67
|
+
- **`/grill-with-docs-codex` / `/grill-me-codex`** — for genuinely hard-to-reverse calls, escalate to a cross-model grill (see Cross-model review).
|
|
68
|
+
<!-- mirror-xform:end -->
|
|
69
|
+
|
|
70
|
+
## On-ramps
|
|
71
|
+
|
|
72
|
+
A starting situation that generates work, then merges onto the main flow.
|
|
73
|
+
|
|
74
|
+
- **Bugs and requests piling up** → **`/triage`**. Moves issues through triage and produces agent-ready issues that `/implement` later picks up. Only for issues **you didn't create** — `/to-issues` output is already agent-ready, don't triage it.
|
|
75
|
+
- **Something's broken** → **`/diagnose`**. For the hard ones: the bug that resists a first glance, the intermittent flake, the regression between two known-good states. Refuses to theorise until it has a **tight feedback loop** — one command that already goes red on *this* bug — then fixes with a regression test. Its post-mortem hands off to **`/improve-codebase-architecture`** when the finding is that there's no good seam.
|
|
76
|
+
- **A huge, foggy effort too big for one agent session** — a greenfield build or a sprawling feature where the way from here to the destination isn't yet visible, and it's still **pre-spec** (before any grill or PRD) → **`/wayfinder`** (user-invoked). It charts a **shared map** of investigation slices on the tracker and resolves them one at a time — producing **decisions, not deliverables** — until the fog lifts and the route is clear, then merges onto the main flow at **`/to-prd`** (or, if the effort turned out small enough, straight to **`/implement`**). Where `/grill-with-docs` sharpens an idea you can hold in one session, wayfinder is for the one you can't. Once an undertaking has already resolved into several independently-shippable waves, `/scale-check` → `/to-waves` stays the primary route.
|
|
77
|
+
- **A backlog to cluster** → **`/board-to-waves`**. Groups an existing board into themed waves when you need to *find* the next wave rather than start fresh.
|
|
78
|
+
- **A whole wave to LAND** → **`/orchestrate-wave`**. When a wave anchor (file-disjoint slices, specs already locked) is ready to build, verify and land end-to-end — often AFK: it dispatches an implementer per slice in its own worktree, integrates serially, verifies centrally, and lands the wave. The execute-and-land node of the wave ladder (`scale-check` → `to-waves`/`board-to-waves` → `orchestrate-wave`). A single slice just goes to `/tdd`.
|
|
79
|
+
|
|
80
|
+
## Cross-model review (Codex)
|
|
81
|
+
|
|
82
|
+
An independent second model catches what one model rationalises. Read-only, bounded.
|
|
83
|
+
|
|
84
|
+
<!-- mirror-xform:start codex-escalation -->
|
|
85
|
+
- **`/grill-me-codex` / `/grill-with-docs-codex`** — run the grill (Act 1), then a *different* model (Codex) adversarially reviews the locked plan (Act 2) before any code.
|
|
86
|
+
<!-- mirror-xform:end -->
|
|
87
|
+
- **`/codex-review`** (Claude Code only) — standalone: you already have a plan, just want the cross-model stress-test.
|
|
88
|
+
|
|
89
|
+
## Codebase health
|
|
90
|
+
|
|
91
|
+
Not feature work — upkeep.
|
|
92
|
+
|
|
93
|
+
- **`/improve-codebase-architecture`** — run in spare moments to keep the codebase good for agents. Surfaces **deepening opportunities**; picking one _generates an idea_ for the main flow at `/grill-with-docs`.
|
|
94
|
+
- **`/zoom-out`** — step back from the diff to the structure when a change is fighting the codebase; recon that becomes a planned slice or guides a refactor in place.
|
|
95
|
+
- **`/security-audit`** — a whole-app, application-layer security audit run as an independent two-model pass (two models audit the same code separately, then the remediation plan is hardened before any fix). Run before a release or after the attack surface changes (new endpoint, new input source, auth change, dependency bump). Infra hardening (ports/TLS/SSH/backups) is audited separately.
|
|
96
|
+
|
|
97
|
+
## Vocabulary underneath
|
|
98
|
+
|
|
99
|
+
Model-invoked references that run *beneath* the other skills — each the single source of truth for its vocabulary. Reach for them when the **words**, not the process, are the problem.
|
|
100
|
+
|
|
101
|
+
- **`/domain-modeling`** — sharpen the project's *domain* language: challenge a fuzzy term, resolve an overloaded word, record a hard-to-reverse decision as an ADR. The active discipline `/grill-with-docs` drives to keep `CONTEXT.md` a clean glossary. (ADR conventions: `docs/adr/README.md`.)
|
|
102
|
+
- **`/codebase-design`** — the deep-module vocabulary (module, interface, depth, seam, adapter, leverage, locality) for designing a module's *shape*. `/tdd` and `/improve-codebase-architecture` both speak it.
|
|
103
|
+
- **`/write-a-skill`** (Claude Code only) — reference for writing and editing skills well (invocation, information hierarchy, progressive disclosure, leading words, pruning, failure modes). *This router is itself an instance of its "router skill" pattern.*
|
|
104
|
+
|
|
105
|
+
## Land
|
|
106
|
+
|
|
107
|
+
- **`/wrapup`** — the land-and-clean closeout: make the branch landable, enforce the PR-body contract, merge, reconcile the board, sweep merged branches, surface what's still open. Does not replace live verification — verify the user outcome first.
|
|
108
|
+
- **`/local-ci`** — the pre-PR gate: run the repo's local CI (fast static guards + the full gate) before opening a PR. When your host can't enforce a required status check at merge (a Free-plan private repo has no branch protection), the gate has to be local — this is it.
|
|
109
|
+
- The **pre-commit / pre-push gate** fires automatically (installed once via `/git-guardrails-claude-code` / `/setup-pre-commit`, both Claude Code only), blocking a broken commit/push.
|
|
110
|
+
|
|
111
|
+
## Learn
|
|
112
|
+
|
|
113
|
+
- **`/retro`** — in-session post-mortem that proposes concrete changes to rules, skills, or hooks, each with per-patch approval.
|
|
114
|
+
- **`/audit-skills`** — the anti-drift audit: check the repo's own skills against code/doc reality and fix the rot (dead paths, stale line numbers, broken cross-refs). Run it periodically or when a SessionStart drift-hint flags a skill whose declared source moved.
|
|
115
|
+
- **`/write-a-skill`** (Claude Code only) — turn a move you keep repeating into a reusable skill (see Vocabulary).
|
|
116
|
+
|
|
117
|
+
## Crossing sessions
|
|
118
|
+
|
|
119
|
+
- **`/handoff`** — compacts the conversation into a markdown file when a thread is full or you need to branch (e.g. into a `/prototype` session). You don't continue in place — open a new session and reference that file. `/handoff` forks; `/compact` continues.
|
|
120
|
+
- **`/compact`** (built-in) — stay in the same conversation, letting earlier turns be summarized. Use at intentional breaks between phases, not mid-phase.
|
|
121
|
+
|
|
122
|
+
## Standalone
|
|
123
|
+
|
|
124
|
+
Off the main flow entirely.
|
|
125
|
+
|
|
126
|
+
- **`/grill-me`** — the same relentless interview as `/grill-with-docs`, but for when you have **no codebase**. Stateless — saves nothing locally.
|
|
127
|
+
- **`/prototype`** — a small throwaway program that answers one design question (does this state model feel right; what should this UI look like). Keep the answer, delete the code.
|
|
128
|
+
- **`/research`** — delegate reading/docs legwork to a **background agent**: it investigates a question against **primary sources** and leaves a cited Markdown note in the repo. Keep working while it reads. Model-invoked (also triggerable by name); the note it produces is something to carry *into* the main flow at `/grill-with-docs` — research feeds the thinking, it doesn't replace it.
|
|
129
|
+
- **`/resolving-merge-conflicts`** — a disciplined loop for an in-progress merge/rebase conflict: understand each side's intent, preserve both where possible, always resolve (never `--abort`).
|
|
130
|
+
- **`/git-worktree-recover`** — reflog recovery for a branch mix-up: a commit landed on the wrong branch, the branch switched unexpectedly, or work looks lost. Finds the misplaced commit, moves it to the right branch, and sets up a clean worktree.
|
|
131
|
+
- **`/spec-self-critique`** — red-team your own spec before committing to build it.
|
|
132
|
+
|
|
133
|
+
## Precondition
|
|
134
|
+
|
|
135
|
+
- **`/setup-workflow`** — run before your first engineering flow to configure the issue tracker, triage labels, board profile, and doc layout the other skills assume.
|
|
136
|
+
|
|
137
|
+
## Repo-specific skills
|
|
138
|
+
|
|
139
|
+
This repo also carries **project-private domain/tooling skills** (data layer, migrations, forecast/risk logic, brand, blast-radius census, …) that don't ship in the kit. For those, see the **project-skill table in `CLAUDE.md`** — they're model-invoked and fire on their own triggers.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Third-Party Notices
|
|
2
|
+
|
|
3
|
+
This skill is adapted from **Matt Pocock's skills**
|
|
4
|
+
(https://github.com/mattpocock/skills), `skills/engineering/ask-matt` @ d574778, Copyright (c) 2026 Matt Pocock,
|
|
5
|
+
used under the MIT License. Locally adapted (fork-and-own); see PROVENANCE.md.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
MIT License
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2026 Matt Pocock
|
|
11
|
+
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
14
|
+
in the Software without restriction, including without limitation the rights
|
|
15
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
16
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
17
|
+
furnished to do so, subject to the following conditions:
|
|
18
|
+
|
|
19
|
+
The above copyright notice and this permission notice shall be included in all
|
|
20
|
+
copies or substantial portions of the Software.
|
|
21
|
+
|
|
22
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
23
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
24
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
25
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
26
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
27
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
28
|
+
SOFTWARE.
|
|
29
|
+
```
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: audit-skills
|
|
3
|
+
disable-model-invocation: true
|
|
4
|
+
description: Audit the project's own skills for drift from code/doc reality and fix it — the anti-drift "learn" step of the plan → execute → land → learn line. Run it at retro, periodically, or when a SessionStart drift-hint warns that a skill's declared source moved since its last touch. Fans out one read-only research subagent per skill over every concrete claim in the SKILL.md, re-verifies each reported drift empirically before editing (the auditor produces false positives), then fixes by content type. Triggers — "audit the skills", "skill drift", "stale skill", "this skill points at a dead path / renamed symbol", "skill-freshness warning". NOT for rewriting a domain skill's content on demand (that is the skill itself) and NOT for auditing application code (that is a code review or a diagnosis).
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# audit-skills — Skill freshness audit (anti-drift)
|
|
8
|
+
|
|
9
|
+
A reusable recipe for checking the project's own skills against code/doc reality
|
|
10
|
+
and keeping them fresh. Skills rot in every repo: a refactor moves a file, a
|
|
11
|
+
symbol is renamed, a line number shifts — and the SKILL.md that named it now
|
|
12
|
+
lies. This is the **learn** step of the plan → execute → land → learn line: the
|
|
13
|
+
skills the other steps rely on drift, and nothing fixes them unless a recipe does.
|
|
14
|
+
|
|
15
|
+
## When to run
|
|
16
|
+
|
|
17
|
+
- At `/retro` (a periodic hygiene point).
|
|
18
|
+
- When the SessionStart drift-hint hook (`.claude/hooks/skill-drift-hint.py`)
|
|
19
|
+
warns that a declared source moved in git since the skill's last touch.
|
|
20
|
+
- Ad-hoc, when a skill you just reached for points at a dead path or a renamed
|
|
21
|
+
symbol.
|
|
22
|
+
|
|
23
|
+
Not for: rewriting a domain skill's content on demand (that is the skill itself),
|
|
24
|
+
or auditing application code (a code review or a diagnosis does that).
|
|
25
|
+
|
|
26
|
+
## Standing guards (run without this audit)
|
|
27
|
+
|
|
28
|
+
Two automatic nets catch the most common drift classes before an audit — this
|
|
29
|
+
recipe complements them, it does not replace them:
|
|
30
|
+
|
|
31
|
+
1. **A skill-sync test** — for any un-guessable enumeration a skill documents (a
|
|
32
|
+
status→bucket map, a design-token list), a test parses the value out of the
|
|
33
|
+
SKILL.md and asserts equality with the code constant. Drift breaks the build.
|
|
34
|
+
Your project layer names the concrete tests.
|
|
35
|
+
2. **The drift-hint hook** (`.claude/hooks/skill-drift-hint.py`) + a per-skill
|
|
36
|
+
`SOURCES.txt`: at SessionStart it flags any skill whose declared source file
|
|
37
|
+
is newer in git than its SKILL.md.
|
|
38
|
+
|
|
39
|
+
**Core insight:** test-covered values do NOT drift silently — only un-tested
|
|
40
|
+
prose refs (paths, line numbers, cross-refs, memory keys) rot. So: test-cover the
|
|
41
|
+
high-value un-guessable enumerations (guard 1); audit everything else
|
|
42
|
+
periodically (this recipe).
|
|
43
|
+
|
|
44
|
+
## The SOURCES.txt convention
|
|
45
|
+
|
|
46
|
+
Each drift-prone skill declares its code/doc anchors in a co-located
|
|
47
|
+
`SOURCES.txt` next to its `SKILL.md`:
|
|
48
|
+
|
|
49
|
+
- one repo-relative source path per line;
|
|
50
|
+
- `#` comments and blank lines are ignored;
|
|
51
|
+
- the drift-hint hook compares each source's last-commit time against the
|
|
52
|
+
SKILL.md's — a source committed *after* the skill means the skill may be stale;
|
|
53
|
+
- committing (touching) the SKILL.md resets the signal — that is how you
|
|
54
|
+
acknowledge that you re-checked it.
|
|
55
|
+
|
|
56
|
+
When a confirmed fix introduces a new source file or replaces an old one, update
|
|
57
|
+
that skill's `SOURCES.txt` in the same change — otherwise the hook keeps pointing
|
|
58
|
+
at dead anchors, or misses the new source.
|
|
59
|
+
|
|
60
|
+
## Recipe
|
|
61
|
+
|
|
62
|
+
### 1. Enumerate the skills — three audit classes
|
|
63
|
+
|
|
64
|
+
Do NOT hardcode a skill list (it rots on every new skill; a newly added skill
|
|
65
|
+
stays blind). Derive it from the skill manifest (`.claude/skills/skill-manifest.json`)
|
|
66
|
+
plus the `SOURCES.txt` files. Sort every skill into one of three classes:
|
|
67
|
+
|
|
68
|
+
1. **Code-drift — subagent-audited, drift-hook-netted.** Every skill with a
|
|
69
|
+
`SOURCES.txt`. The hook already watches these; run a full step-2 subagent
|
|
70
|
+
audit over each file/symbol/line claim.
|
|
71
|
+
```bash
|
|
72
|
+
ls .claude/skills/*/SOURCES.txt # → the drift-netted skills
|
|
73
|
+
```
|
|
74
|
+
2. **Project-layer drift — against docs, not code.** Published/genericized skills
|
|
75
|
+
carry their project crust in a project-layer doc, not in code. Lighter check:
|
|
76
|
+
do the inline pointers still resolve to existing project-layer files, and do
|
|
77
|
+
the cited field/status names still match the profile.
|
|
78
|
+
3. **Script-coupled, un-netted — checked by hand every audit.** Skills coupled to
|
|
79
|
+
scripts or hooks with no `SOURCES.txt` and no hook net. No hook warns, so
|
|
80
|
+
re-check them manually each audit.
|
|
81
|
+
|
|
82
|
+
Your project layer assigns each concrete skill to a class — a completeness gate
|
|
83
|
+
catches the next new skill that would otherwise stay invisible.
|
|
84
|
+
|
|
85
|
+
### 2. Audit in parallel — one subagent per skill
|
|
86
|
+
|
|
87
|
+
Run **one read-only research subagent per skill** — several in parallel in a
|
|
88
|
+
SINGLE message (they are independent and read-only, so they don't contend for the
|
|
89
|
+
git index). Per subagent prompt:
|
|
90
|
+
|
|
91
|
+
- name the repo root, insist **read-only**, "propose no fixes";
|
|
92
|
+
- list **each concrete SKILL.md claim** separately: file path, symbol name, line
|
|
93
|
+
number, code example, cross-ref, memory key;
|
|
94
|
+
- ask for a verdict table back — `TRUE / FALSE / PARTIAL` + the CURRENT real
|
|
95
|
+
path/symbol/signature — in compact `file:line` form (far fewer tokens than
|
|
96
|
+
inline reads).
|
|
97
|
+
|
|
98
|
+
### 3. Re-verify before every edit — mandatory
|
|
99
|
+
|
|
100
|
+
**The auditor produces false positives.** Treat every reported drift as a
|
|
101
|
+
hypothesis, not a fact: re-verify it at the edit itself (`grep` / read the file)
|
|
102
|
+
before changing anything. Never take the auditor's list blind — and an empty
|
|
103
|
+
`grep` result is not proof either, so anchor the search frame (path from the repo
|
|
104
|
+
root, grep the import line, try a second pattern variant). On low-confidence
|
|
105
|
+
findings, re-audit the whole skill rather than trusting the list. This
|
|
106
|
+
false-positive discipline is the single most important rule of the recipe.
|
|
107
|
+
|
|
108
|
+
### 4. Fix only what's confirmed — by content type
|
|
109
|
+
|
|
110
|
+
- **Line number** → reference the symbol (function / constant); keep a line only
|
|
111
|
+
when unavoidable.
|
|
112
|
+
- **Dead path** → the correct path, OR a pointer to the single source of truth.
|
|
113
|
+
- **Cross-ref** → a stable name (verify the target still exists first).
|
|
114
|
+
- **Stale "must still fix" state-claim** → move it into a "historical" block
|
|
115
|
+
(keep the lesson, don't present it as current) or delete it.
|
|
116
|
+
- **Real code finding** (the skill is right, the code drifted) → a **separate
|
|
117
|
+
issue**, NOT fixed inside the docs change.
|
|
118
|
+
- **Test-covered values** → leave untouched (guard 1 already secures them).
|
|
119
|
+
|
|
120
|
+
### 5. Catch up the SOURCES.txt
|
|
121
|
+
|
|
122
|
+
If a confirmed fix introduced a new source file or replaced an old one, update
|
|
123
|
+
the affected skill's `SOURCES.txt` in the same change (see the convention above).
|
|
124
|
+
|
|
125
|
+
### 5b. Sync any second surface
|
|
126
|
+
|
|
127
|
+
If your skills are published to more than one surface (for example a Codex mirror
|
|
128
|
+
alongside the Claude source), sync the mirror in the **same** change — otherwise
|
|
129
|
+
the second surface rots silently. Mirror the body, but preserve each surface's
|
|
130
|
+
own frontmatter: a mirror's `description` may be deliberately condensed, so never
|
|
131
|
+
blind-copy the whole file over it. A `SOURCES.txt` is a plain anchor list and can
|
|
132
|
+
be mirrored verbatim. Your project layer names the surfaces and the exact
|
|
133
|
+
transform.
|
|
134
|
+
|
|
135
|
+
## Done
|
|
136
|
+
|
|
137
|
+
- **Enumeration completeness:** every skill from the manifest is assigned to one
|
|
138
|
+
of the three §1 classes — this catches the next new skill that would otherwise
|
|
139
|
+
stay invisible to the audit.
|
|
140
|
+
- Every reported drift is either fixed (with re-verify proof) or dismissed as a
|
|
141
|
+
false positive (with proof the skill was right).
|
|
142
|
+
- Real code findings filed as their own issues, not folded into the docs change.
|
|
143
|
+
- Any second surface synced (body-parity; each surface's frontmatter preserved).
|
|
144
|
+
- The skill-sync guard and the drift-hint smoke test pass.
|
|
145
|
+
- A pure docs / test / hook change needs no application live-verify.
|