claude-dev-env 1.93.0 → 1.94.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/_shared/pr-loop/CLAUDE.md +1 -0
- package/_shared/pr-loop/audit-contract.md +1 -1
- package/_shared/pr-loop/gh-payloads.md +3 -3
- package/_shared/pr-loop/post-audit-thread-contract.md +51 -0
- package/_shared/pr-loop/scripts/README.md +2 -2
- package/_shared/pr-loop/scripts/code_rules_gate.py +127 -13
- package/_shared/pr-loop/scripts/fix_hookspath.py +47 -12
- package/_shared/pr-loop/scripts/pr_loop_shared_constants/code_rules_gate_constants.py +4 -0
- package/_shared/pr-loop/scripts/tests/test_code_rules_gate.py +146 -69
- package/_shared/pr-loop/scripts/tests/test_fix_hookspath.py +497 -374
- package/_shared/pr-loop/state-schema.md +3 -22
- package/bin/CLAUDE.md +1 -1
- package/bin/install.mjs +2 -7
- package/bin/install.test.mjs +10 -4
- package/hooks/blocking/CLAUDE.md +2 -0
- package/hooks/blocking/pii_commit_command.py +398 -0
- package/hooks/blocking/pii_payload_scan.py +133 -0
- package/hooks/blocking/pii_prevention_blocker.py +151 -449
- package/hooks/blocking/pii_scanner.py +26 -1
- package/hooks/blocking/test_code_rules_enforcer_dead_config_field.py +2 -2
- package/hooks/blocking/test_pii_prevention_blocker.py +299 -0
- package/hooks/blocking/test_pii_scanner.py +27 -2
- package/hooks/blocking/test_verdict_directory_write_blocker.py +42 -7
- package/hooks/hooks_constants/CLAUDE.md +2 -2
- package/hooks/hooks_constants/code_rules_path_utils_constants.py +0 -2
- package/hooks/hooks_constants/local_identity.py +65 -15
- package/hooks/hooks_constants/pii_prevention_constants.py +20 -8
- package/hooks/hooks_constants/pr_description_enforcer_constants.py +1 -1
- package/hooks/hooks_constants/test_local_identity.py +68 -0
- package/package.json +1 -1
- package/scripts/CLAUDE.md +10 -1
- package/scripts/Get-SessionAccount.ps1 +210 -0
- package/scripts/tests/CLAUDE.md +15 -1
- package/scripts/tests/Get-SessionAccount.Tests.ps1 +350 -0
- package/skills/CLAUDE.md +3 -25
- package/skills/anthropic-plan/SKILL.md +1 -13
- package/skills/autoconverge/CLAUDE.md +5 -2
- package/skills/autoconverge/SKILL.md +112 -387
- package/skills/autoconverge/reference/CLAUDE.md +4 -1
- package/skills/autoconverge/reference/closing-report.md +9 -2
- package/skills/autoconverge/reference/convergence.md +26 -22
- package/skills/autoconverge/reference/headless-safety.md +44 -0
- package/skills/autoconverge/reference/multi-pr.md +88 -0
- package/skills/autoconverge/reference/self-closing-loop.md +84 -0
- package/skills/autoconverge/reference/stop-conditions.md +21 -13
- package/skills/autoconverge/workflow/converge.clean-audit.test.mjs +87 -27
- package/skills/autoconverge/workflow/converge.contract.test.mjs +40 -10
- package/skills/autoconverge/workflow/converge.copilot-gate.test.mjs +179 -47
- package/skills/autoconverge/workflow/converge.fix-progress.test.mjs +1 -1
- package/skills/autoconverge/workflow/converge.mjs +284 -94
- package/skills/bugteam/CLAUDE.md +1 -1
- package/skills/bugteam/CONSTRAINTS.md +3 -3
- package/skills/bugteam/PROMPTS.md +8 -19
- package/skills/bugteam/SKILL.md +13 -14
- package/skills/bugteam/reference/CLAUDE.md +1 -1
- package/skills/bugteam/reference/audit-and-teammates.md +2 -2
- package/skills/bugteam/reference/copilot-gap-analysis.md +2 -0
- package/skills/bugteam/reference/github-pr-reviews.md +56 -38
- package/skills/bugteam/reference/team-setup.md +11 -11
- package/skills/bugteam/scripts/CLAUDE.md +6 -6
- package/skills/bugteam/scripts/README.md +20 -8
- package/skills/bugteam/scripts/bugteam_code_rules_gate.py +13 -1463
- package/skills/bugteam/scripts/bugteam_fix_hookspath.py +23 -358
- package/skills/bugteam/scripts/bugteam_preflight.py +13 -315
- package/skills/bugteam/scripts/bugteam_scripts_constants/CLAUDE.md +2 -3
- package/skills/bugteam/scripts/test_bugteam_code_rules_gate.py +34 -1053
- package/skills/bugteam/scripts/test_bugteam_fix_hookspath.py +30 -347
- package/skills/bugteam/scripts/test_bugteam_preflight.py +30 -305
- package/skills/copilot-finding-triage/SKILL.md +80 -28
- package/skills/copilot-finding-triage/reference/tier-rubric.md +70 -11
- package/skills/copilot-finding-triage/templates/notification.md +8 -3
- package/skills/everything-search/SKILL.md +1 -2
- package/skills/grokify/SKILL.md +58 -0
- package/skills/grokify/templates/handoff-template.md +92 -0
- package/skills/orchestrator/SKILL.md +12 -8
- package/skills/orchestrator-refresh/SKILL.md +3 -3
- package/skills/pr-converge/SKILL.md +132 -233
- package/skills/pr-converge/reference/convergence-gates.md +102 -66
- package/skills/pr-converge/reference/examples.md +37 -25
- package/skills/pr-converge/reference/fix-protocol.md +7 -7
- package/skills/pr-converge/reference/multi-pr-orchestration.md +10 -4
- package/skills/pr-converge/reference/per-tick.md +64 -41
- package/skills/pr-converge/reference/state-schema.md +27 -2
- package/skills/pr-converge/scripts/CLAUDE.md +8 -0
- package/skills/pr-converge/scripts/README.md +4 -3
- package/skills/pr-converge/scripts/_pr_converge_path_setup.py +23 -0
- package/skills/pr-converge/scripts/check_convergence.py +189 -645
- package/skills/pr-converge/scripts/check_convergence_gates.py +235 -0
- package/skills/pr-converge/scripts/check_convergence_thread_gates.py +219 -0
- package/skills/pr-converge/scripts/conftest.py +8 -0
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/CLAUDE.md +1 -0
- package/skills/pr-converge/scripts/pr_converge_scripts_constants/convergence_gate_constants.py +36 -0
- package/skills/pr-converge/scripts/test__pr_converge_path_setup.py +26 -0
- package/skills/pr-converge/scripts/test_check_convergence.py +73 -228
- package/skills/pr-converge/scripts/test_check_convergence_contract.py +321 -0
- package/skills/pr-converge/scripts/test_check_convergence_gates.py +68 -0
- package/skills/pr-converge/scripts/test_check_convergence_thread_gates.py +75 -0
- package/skills/privacy-hygiene/SKILL.md +8 -7
- package/skills/reviewer-gates/SKILL.md +26 -8
- package/skills/session-log/SKILL.md +11 -12
- package/skills/session-tidy/SKILL.md +40 -30
- package/skills/skill-builder/CLAUDE.md +13 -10
- package/skills/skill-builder/SKILL.md +31 -31
- package/skills/skill-builder/references/CLAUDE.md +10 -6
- package/skills/skill-builder/references/delegation-map.md +13 -4
- package/skills/skill-builder/references/description-field.md +113 -0
- package/skills/skill-builder/references/self-audit-checklist.md +21 -4
- package/skills/skill-builder/references/skill-modularity.md +113 -0
- package/skills/skill-builder/references/skill-types.md +4 -0
- package/skills/skill-builder/templates/CLAUDE.md +4 -4
- package/skills/skill-builder/templates/gap-analysis.md +25 -1
- package/skills/skill-builder/workflows/CLAUDE.md +6 -4
- package/skills/skill-builder/workflows/improve-skill.md +17 -16
- package/skills/skill-builder/workflows/new-skill.md +34 -10
- package/skills/skill-builder/workflows/polish-skill.md +59 -43
- package/skills/usage-pause/SKILL.md +10 -14
- package/skills/bdd-protocol/CLAUDE.md +0 -26
- package/skills/bdd-protocol/SKILL.md +0 -30
- package/skills/bdd-protocol/references/CLAUDE.md +0 -10
- package/skills/bdd-protocol/references/anti-patterns.md +0 -26
- package/skills/bdd-protocol/references/example-mapping.md +0 -23
- package/skills/bg-agent/CLAUDE.md +0 -17
- package/skills/bg-agent/SKILL.md +0 -69
- package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_code_rules_gate_constants.py +0 -55
- package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_fix_hookspath_constants.py +0 -26
- package/skills/bugteam/scripts/bugteam_scripts_constants/bugteam_preflight_constants.py +0 -35
- package/skills/caveman/CLAUDE.md +0 -15
- package/skills/caveman/SKILL.md +0 -38
- package/skills/code/CLAUDE.md +0 -17
- package/skills/code/SKILL.md +0 -178
- package/skills/deep-research/CLAUDE.md +0 -17
- package/skills/deep-research/SKILL.md +0 -80
- package/skills/findbugs/CLAUDE.md +0 -20
- package/skills/findbugs/SKILL.md +0 -241
- package/skills/fixbugs/CLAUDE.md +0 -19
- package/skills/fixbugs/SKILL.md +0 -142
- package/skills/gh-paginate/CLAUDE.md +0 -18
- package/skills/gh-paginate/SKILL.md +0 -84
- package/skills/gotcha/CLAUDE.md +0 -33
- package/skills/gotcha/SKILL.md +0 -73
- package/skills/implement/CLAUDE.md +0 -27
- package/skills/implement/SKILL.md +0 -66
- package/skills/implement/scripts/CLAUDE.md +0 -22
- package/skills/implement/scripts/append_note.py +0 -133
- package/skills/implement/scripts/implement_scripts_constants/CLAUDE.md +0 -22
- package/skills/implement/scripts/implement_scripts_constants/__init__.py +0 -0
- package/skills/implement/scripts/implement_scripts_constants/notes_constants.py +0 -12
- package/skills/implement/scripts/test_append_note.py +0 -191
- package/skills/log-audit/CLAUDE.md +0 -20
- package/skills/log-audit/SKILL.md +0 -66
- package/skills/log-audit/reference/CLAUDE.md +0 -9
- package/skills/log-audit/reference/charter.md +0 -52
- package/skills/log-audit/scripts/CLAUDE.md +0 -27
- package/skills/log-audit/scripts/cluster_recurrences.py +0 -261
- package/skills/log-audit/scripts/collect_log_window.py +0 -199
- package/skills/log-audit/scripts/log_audit_constants/CLAUDE.md +0 -12
- package/skills/log-audit/scripts/log_audit_constants/__init__.py +0 -0
- package/skills/log-audit/scripts/log_audit_constants/cluster_recurrences_constants.py +0 -23
- package/skills/log-audit/scripts/log_audit_constants/collect_log_window_constants.py +0 -24
- package/skills/log-audit/scripts/log_audit_constants/mine_copilot_findings_constants.py +0 -49
- package/skills/log-audit/scripts/mine_copilot_findings.py +0 -302
- package/skills/log-audit/scripts/test_cluster_recurrences.py +0 -160
- package/skills/log-audit/scripts/test_collect_log_window.py +0 -111
- package/skills/log-audit/scripts/test_mine_copilot_findings.py +0 -126
- package/skills/logifix/CLAUDE.md +0 -36
- package/skills/logifix/SKILL.md +0 -69
- package/skills/logifix/scripts/CLAUDE.md +0 -16
- package/skills/logifix/scripts/logifix.ps1 +0 -205
- package/skills/monitor-open-prs/CLAUDE.md +0 -34
- package/skills/monitor-open-prs/SKILL.md +0 -88
- package/skills/monitor-open-prs/scripts/CLAUDE.md +0 -17
- package/skills/monitor-open-prs/scripts/discover_open_prs.py +0 -69
- package/skills/monitor-open-prs/scripts/test_discover_open_prs.py +0 -149
- package/skills/monitor-open-prs/test_skill_contract.py +0 -27
- package/skills/post-audit-findings/SKILL.md +0 -80
- package/skills/pr-consistency-audit/CLAUDE.md +0 -34
- package/skills/pr-consistency-audit/SKILL.md +0 -116
- package/skills/pr-consistency-audit/reference/CLAUDE.md +0 -16
- package/skills/pr-consistency-audit/reference/detection-rules.md +0 -96
- package/skills/pr-consistency-audit/reference/illustrations.md +0 -78
- package/skills/pr-fix-protocol/SKILL.md +0 -65
- package/skills/pr-review-responder/CLAUDE.md +0 -35
- package/skills/pr-review-responder/EXAMPLES.md +0 -590
- package/skills/pr-review-responder/PRINCIPLES.md +0 -533
- package/skills/pr-review-responder/README.md +0 -168
- package/skills/pr-review-responder/SKILL.md +0 -203
- package/skills/pr-review-responder/TESTING.md +0 -350
- package/skills/pr-scope-resolve/SKILL.md +0 -45
- package/skills/pre-compact/CLAUDE.md +0 -24
- package/skills/pre-compact/SKILL.md +0 -134
- package/skills/qbug/CLAUDE.md +0 -40
- package/skills/qbug/SKILL.md +0 -387
- package/skills/qbug/test_qbug_skill_audit_schema.py +0 -152
- package/skills/qbug/test_qbug_skill_post_fix_audit.py +0 -103
- package/skills/refine/CLAUDE.md +0 -44
- package/skills/refine/SKILL.md +0 -262
- package/skills/refine/templates/CLAUDE.md +0 -17
- package/skills/refine/templates/implementation-notes-template.html +0 -56
- package/skills/refine/templates/plan-template.md +0 -60
- package/skills/research-mode/CLAUDE.md +0 -35
- package/skills/research-mode/SKILL.md +0 -53
- package/skills/structure-prompt/CLAUDE.md +0 -42
- package/skills/structure-prompt/SKILL.md +0 -44
- package/skills/structure-prompt/reference/CLAUDE.md +0 -28
- package/skills/structure-prompt/reference/adversarial-tuning.md +0 -62
- package/skills/structure-prompt/reference/block-classification.md +0 -27
- package/skills/structure-prompt/reference/canonical-case.md +0 -48
- package/skills/structure-prompt/reference/citation-depth.md +0 -70
- package/skills/structure-prompt/reference/cleanup.md +0 -33
- package/skills/structure-prompt/reference/constraints.md +0 -33
- package/skills/structure-prompt/reference/directives.md +0 -37
- package/skills/structure-prompt/reference/examples.md +0 -72
- package/skills/structure-prompt/reference/instantiation.md +0 -51
- package/skills/structure-prompt/reference/output-contract.md +0 -72
- package/skills/structure-prompt/reference/per-category.md +0 -23
- package/skills/structure-prompt/reference/persona.md +0 -38
- package/skills/structure-prompt/reference/research.md +0 -33
- package/skills/structure-prompt/reference/structure.md +0 -28
- package/skills/verified-build/CLAUDE.md +0 -33
- package/skills/verified-build/SKILL.md +0 -33
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# Spec Execution Skill
|
|
2
|
-
|
|
3
|
-
This skill (`implement`) runs a spec end-to-end while maintaining a sidecar `implementation-notes.html` that records design decisions, deviations, tradeoffs, and open questions made during the build.
|
|
4
|
-
|
|
5
|
-
**Trigger:** `/implement [path-to-spec]`, "build out this plan and keep notes".
|
|
6
|
-
|
|
7
|
-
## Key files
|
|
8
|
-
|
|
9
|
-
| File | Purpose |
|
|
10
|
-
|---|---|
|
|
11
|
-
| `SKILL.md` | Full workflow: resolve spec, run it, write notes via `append_note.py` |
|
|
12
|
-
| `packages/claude-dev-env/skills/implement/scripts/append_note.py` | CLI that creates or appends to `implementation-notes.html` |
|
|
13
|
-
| `packages/claude-dev-env/skills/implement/scripts/implement_scripts_constants/notes_constants.py` | Section slugs → headings and default filename |
|
|
14
|
-
|
|
15
|
-
## Subdirectories
|
|
16
|
-
|
|
17
|
-
| Directory | Role |
|
|
18
|
-
|---|---|
|
|
19
|
-
| `scripts/` | Python CLI and constants for the notes file |
|
|
20
|
-
|
|
21
|
-
## Conventions
|
|
22
|
-
|
|
23
|
-
- The spec is taken from `$ARGUMENTS` (path) or the most recent plan in conversation context. If neither is present, the skill asks via `AskUserQuestion`.
|
|
24
|
-
- Notes are appended as decisions are made — not batched at the end.
|
|
25
|
-
- The `append_note.py` CLI accepts `--section decisions|deviations|tradeoffs|questions`, `--about`, `--note`, and optionally `--file`. When `--file` is omitted, the script writes to `./implementation-notes.html`.
|
|
26
|
-
- `$CLAUDE_SKILL_DIR` is substituted by Claude Code at runtime so the bundled script is found regardless of the current working directory.
|
|
27
|
-
- The notes file structure must not be hand-edited — `append_note.py` locates sections by `<section id="...">` markers and the first `</ul>` after each.
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: implement
|
|
3
|
-
description: "Implement a spec while maintaining a running implementation-notes.html file that captures design decisions, deviations, tradeoffs, and open questions. Triggers: /implement, implement this spec, build out this plan and keep notes."
|
|
4
|
-
argument-hint: "[path to spec file, or omit to use a spec already in context]"
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
# implement
|
|
8
|
-
|
|
9
|
-
Execute a spec end-to-end while keeping a sidecar `implementation-notes.html` that the user can read to see how the build diverged from or interpreted the written plan.
|
|
10
|
-
|
|
11
|
-
## Instructions
|
|
12
|
-
|
|
13
|
-
Carry out the following prompt against the spec resolved below.
|
|
14
|
-
|
|
15
|
-
### Resolve `<SPEC>`
|
|
16
|
-
|
|
17
|
-
- If `$ARGUMENTS` is non-empty, treat it as the path to the spec file and read it.
|
|
18
|
-
- Otherwise, use the most recent plan / spec / design doc already present in the conversation context.
|
|
19
|
-
- If neither is available, ask the user for the spec path via `AskUserQuestion` before proceeding.
|
|
20
|
-
|
|
21
|
-
### Prompt to execute
|
|
22
|
-
|
|
23
|
-
> Implement `<SPEC>`. As you work maintain a running `implementation-notes.html` file that captures anything I should know about how the implementation diverges from or interprets the spec, including:
|
|
24
|
-
>
|
|
25
|
-
> - **Design decisions:** choices you made where the spec was ambiguous
|
|
26
|
-
> - **Deviations:** places where you intentionally departed from the spec, and why
|
|
27
|
-
> - **Tradeoffs:** alternatives you considered and why you picked what you did
|
|
28
|
-
> - **Open questions:** anything you'd want me to confirm or revise
|
|
29
|
-
|
|
30
|
-
### How to write notes
|
|
31
|
-
|
|
32
|
-
Run `${CLAUDE_SKILL_DIR}/scripts/append_note.py` to append each entry. The script creates `implementation-notes.html` with the four sections on first run, then inserts a new `<li>` under the requested section. HTML-escapes `--about` and `--note` automatically. `${CLAUDE_SKILL_DIR}` is host-substituted by Claude Code at runtime so the bundled CLI is found regardless of the current working directory.
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
python "${CLAUDE_SKILL_DIR}/scripts/append_note.py" \
|
|
36
|
-
--section decisions \
|
|
37
|
-
--about "Storage location" \
|
|
38
|
-
--note "Wrote notes next to the spec because the spec path was provided." \
|
|
39
|
-
--file /path/to/spec-dir/implementation-notes.html
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
`--section` choices (slug → heading):
|
|
43
|
-
|
|
44
|
-
| Slug | Heading |
|
|
45
|
-
|---|---|
|
|
46
|
-
| `decisions` | Design decisions |
|
|
47
|
-
| `deviations` | Deviations |
|
|
48
|
-
| `tradeoffs` | Tradeoffs |
|
|
49
|
-
| `questions` | Open questions |
|
|
50
|
-
|
|
51
|
-
`--file` is optional. When omitted, the script writes to `./implementation-notes.html` in the current working directory. When a spec path is known, pass `--file` so notes land next to the spec rather than in CWD.
|
|
52
|
-
|
|
53
|
-
Append entries as decisions are made — do not batch them until the end.
|
|
54
|
-
|
|
55
|
-
## Gotchas
|
|
56
|
-
|
|
57
|
-
- **Do not hand-edit `implementation-notes.html`.** The append script locates each section by its `<section id="...">` marker and the first `</ul>` after it. Editing the structure breaks subsequent appends; the script raises a `RuntimeError` naming the missing marker.
|
|
58
|
-
- **`--about` and `--note` are HTML-escaped automatically** — pass raw text, not pre-escaped HTML.
|
|
59
|
-
|
|
60
|
-
## File index
|
|
61
|
-
|
|
62
|
-
| File | Purpose |
|
|
63
|
-
|---|---|
|
|
64
|
-
| `SKILL.md` | This hub |
|
|
65
|
-
| `packages/claude-dev-env/skills/implement/scripts/append_note.py` | CLI to append one entry to a section |
|
|
66
|
-
| `packages/claude-dev-env/skills/implement/scripts/implement_scripts_constants/notes_constants.py` | Section slugs → headings and default filename |
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# scripts (spec-build skill)
|
|
2
|
-
|
|
3
|
-
Support scripts for the spec-build (`implement`) skill. These scripts create and append to the `implementation-notes.html` sidecar file the skill maintains during a spec build.
|
|
4
|
-
|
|
5
|
-
## Key files
|
|
6
|
-
|
|
7
|
-
| File | Purpose |
|
|
8
|
-
|---|---|
|
|
9
|
-
| `append_note.py` | CLI that creates `implementation-notes.html` with four sections on first run and appends a `<li>` to a named section on later runs |
|
|
10
|
-
| `test_append_note.py` | Tests for `append_note.py` |
|
|
11
|
-
|
|
12
|
-
## Subdirectories
|
|
13
|
-
|
|
14
|
-
| Directory | Role |
|
|
15
|
-
|---|---|
|
|
16
|
-
| `implement_scripts_constants/` | Section slug → heading map and default filename constant |
|
|
17
|
-
|
|
18
|
-
## Conventions
|
|
19
|
-
|
|
20
|
-
- `append_note.py` imports section metadata from `implement_scripts_constants.notes_constants`.
|
|
21
|
-
- HTML-escaping of `--about` and `--note` is handled by the script; callers pass raw text.
|
|
22
|
-
- The script is invoked as `python "${CLAUDE_SKILL_DIR}/scripts/append_note.py"` from within the skill, where `$CLAUDE_SKILL_DIR` resolves to the installed skill directory at runtime.
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""Append an entry to implementation-notes.html under one of four sections.
|
|
3
|
-
|
|
4
|
-
Used by the `implement` skill. Creates the file with all four sections if it
|
|
5
|
-
does not exist; otherwise appends a new <li> under the requested section.
|
|
6
|
-
|
|
7
|
-
Usage:
|
|
8
|
-
python append_note.py --section decisions --about "Where to write the file" --note "Wrote next to spec rather than CWD because spec path was known."
|
|
9
|
-
python append_note.py --section questions --about "Auth model" --note "Spec didn't say whether sessions persist across restarts." --file ./notes.html
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
from __future__ import annotations
|
|
13
|
-
|
|
14
|
-
import argparse
|
|
15
|
-
import html
|
|
16
|
-
import sys
|
|
17
|
-
from pathlib import Path
|
|
18
|
-
|
|
19
|
-
from implement_scripts_constants.notes_constants import DEFAULT_NOTES_FILENAME, HEADING_BY_SLUG
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def _build_skeleton() -> str:
|
|
23
|
-
section_blocks = "\n".join(
|
|
24
|
-
f' <section id="{each_slug}">\n <h2>{each_heading}</h2>\n <ul></ul>\n </section>'
|
|
25
|
-
for each_slug, each_heading in HEADING_BY_SLUG.items()
|
|
26
|
-
)
|
|
27
|
-
return (
|
|
28
|
-
"<!doctype html>\n"
|
|
29
|
-
'<html lang="en">\n'
|
|
30
|
-
"<head>\n"
|
|
31
|
-
' <meta charset="utf-8">\n'
|
|
32
|
-
" <title>Implementation notes</title>\n"
|
|
33
|
-
"</head>\n"
|
|
34
|
-
"<body>\n"
|
|
35
|
-
" <h1>Implementation notes</h1>\n"
|
|
36
|
-
f"{section_blocks}\n"
|
|
37
|
-
"</body>\n"
|
|
38
|
-
"</html>\n"
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def _ensure_file(target: Path) -> str:
|
|
43
|
-
if not target.exists():
|
|
44
|
-
target.parent.mkdir(parents=True, exist_ok=True)
|
|
45
|
-
skeleton = _build_skeleton()
|
|
46
|
-
target.write_text(skeleton, encoding="utf-8")
|
|
47
|
-
return skeleton
|
|
48
|
-
return target.read_text(encoding="utf-8")
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def _render_entry(about: str, note: str) -> str:
|
|
52
|
-
return f"<li><strong>{html.escape(about)}:</strong> {html.escape(note)}</li>"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def _insert_entry(document: str, slug: str, entry: str) -> str:
|
|
56
|
-
open_marker = f'<section id="{slug}">'
|
|
57
|
-
section_close_marker = "</section>"
|
|
58
|
-
close_marker = "</ul>"
|
|
59
|
-
section_start = document.find(open_marker)
|
|
60
|
-
if section_start == -1:
|
|
61
|
-
raise RuntimeError(
|
|
62
|
-
f"section '{slug}' not found in file — the file may have been "
|
|
63
|
-
f"edited by hand. Restore the four <section id=...> blocks or "
|
|
64
|
-
f"delete the file so it can be regenerated."
|
|
65
|
-
)
|
|
66
|
-
section_end = document.find(section_close_marker, section_start)
|
|
67
|
-
if section_end == -1:
|
|
68
|
-
raise RuntimeError(
|
|
69
|
-
f"section '{slug}' is missing its closing </section> — the file "
|
|
70
|
-
f"may have been edited by hand."
|
|
71
|
-
)
|
|
72
|
-
close_at = document.find(close_marker, section_start, section_end)
|
|
73
|
-
if close_at == -1:
|
|
74
|
-
raise RuntimeError(
|
|
75
|
-
f"section '{slug}' is missing its closing </ul> — the file may "
|
|
76
|
-
f"have been edited by hand."
|
|
77
|
-
)
|
|
78
|
-
boundary = close_at
|
|
79
|
-
while boundary > 0 and document[boundary - 1] in (" ", "\n"):
|
|
80
|
-
boundary -= 1
|
|
81
|
-
new_line = f"\n {entry}"
|
|
82
|
-
return document[:boundary] + new_line + "\n " + document[close_at:]
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def _parse_arguments() -> argparse.Namespace:
|
|
86
|
-
parser = argparse.ArgumentParser(
|
|
87
|
-
description=f"Append an entry to {DEFAULT_NOTES_FILENAME}.",
|
|
88
|
-
)
|
|
89
|
-
parser.add_argument(
|
|
90
|
-
"--section",
|
|
91
|
-
required=True,
|
|
92
|
-
choices=sorted(HEADING_BY_SLUG.keys()),
|
|
93
|
-
help="Which section to append under.",
|
|
94
|
-
)
|
|
95
|
-
parser.add_argument(
|
|
96
|
-
"--about",
|
|
97
|
-
required=True,
|
|
98
|
-
help="Short label naming the part of the spec this entry relates to.",
|
|
99
|
-
)
|
|
100
|
-
parser.add_argument(
|
|
101
|
-
"--note",
|
|
102
|
-
required=True,
|
|
103
|
-
help="The decision / deviation / tradeoff / question itself.",
|
|
104
|
-
)
|
|
105
|
-
parser.add_argument(
|
|
106
|
-
"--file",
|
|
107
|
-
default=DEFAULT_NOTES_FILENAME,
|
|
108
|
-
help=(
|
|
109
|
-
f"Path to the notes file. Defaults to ./{DEFAULT_NOTES_FILENAME} "
|
|
110
|
-
f"in the current working directory."
|
|
111
|
-
),
|
|
112
|
-
)
|
|
113
|
-
return parser.parse_args()
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
def main() -> int:
|
|
117
|
-
"""Parse CLI arguments and append one entry to the notes file.
|
|
118
|
-
|
|
119
|
-
Returns:
|
|
120
|
-
Process exit code (0 on success).
|
|
121
|
-
"""
|
|
122
|
-
arguments = _parse_arguments()
|
|
123
|
-
target_path = Path(arguments.file).expanduser().resolve()
|
|
124
|
-
document = _ensure_file(target_path)
|
|
125
|
-
entry = _render_entry(arguments.about, arguments.note)
|
|
126
|
-
updated = _insert_entry(document, arguments.section, entry)
|
|
127
|
-
target_path.write_text(updated, encoding="utf-8")
|
|
128
|
-
print(f"appended to [{arguments.section}] in {target_path}")
|
|
129
|
-
return 0
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if __name__ == "__main__":
|
|
133
|
-
sys.exit(main())
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# implement_scripts_constants
|
|
2
|
-
|
|
3
|
-
Constants module for the `implement` skill's `append_note.py` script.
|
|
4
|
-
|
|
5
|
-
## Key files
|
|
6
|
-
|
|
7
|
-
| File | Purpose |
|
|
8
|
-
|---|---|
|
|
9
|
-
| `__init__.py` | Package marker |
|
|
10
|
-
| `notes_constants.py` | `HEADING_BY_SLUG` dict (section slugs → display headings) and `DEFAULT_NOTES_FILENAME` |
|
|
11
|
-
|
|
12
|
-
## Exported constants
|
|
13
|
-
|
|
14
|
-
| Constant | Value | Used by |
|
|
15
|
-
|---|---|---|
|
|
16
|
-
| `HEADING_BY_SLUG` | `{"decisions": "Design decisions", "deviations": "Deviations", "tradeoffs": "Tradeoffs", "questions": "Open questions"}` | `append_note.py` — maps `--section` slug to the `<h2>` heading in the HTML file |
|
|
17
|
-
| `DEFAULT_NOTES_FILENAME` | `"implementation-notes.html"` | `append_note.py` — default output path when `--file` is omitted |
|
|
18
|
-
|
|
19
|
-
## Conventions
|
|
20
|
-
|
|
21
|
-
- This module is imported directly by `append_note.py` in the parent `scripts/` directory.
|
|
22
|
-
- Adding a new section requires a new entry in `HEADING_BY_SLUG` and a matching branch in `append_note.py`.
|
|
File without changes
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"""Configuration for the implementation-notes append script."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
HEADING_BY_SLUG: dict[str, str] = {
|
|
6
|
-
"decisions": "Design decisions",
|
|
7
|
-
"deviations": "Deviations",
|
|
8
|
-
"tradeoffs": "Tradeoffs",
|
|
9
|
-
"questions": "Open questions",
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
DEFAULT_NOTES_FILENAME = "implementation-notes.html"
|
|
@@ -1,191 +0,0 @@
|
|
|
1
|
-
"""Tests for append_note.
|
|
2
|
-
|
|
3
|
-
Covers:
|
|
4
|
-
- _build_skeleton emits a four-section HTML document keyed by every slug
|
|
5
|
-
- _ensure_file creates a fresh file on first call and round-trips on subsequent calls
|
|
6
|
-
- _render_entry HTML-escapes the about label and the note body
|
|
7
|
-
- _insert_entry puts the first <li> on its own line and keeps a 6-space indent across entries
|
|
8
|
-
- _insert_entry raises a descriptive RuntimeError when the section block is missing
|
|
9
|
-
- _insert_entry raises a descriptive RuntimeError when the closing </ul> is missing
|
|
10
|
-
- main appends through the CLI surface against a real on-disk file
|
|
11
|
-
"""
|
|
12
|
-
|
|
13
|
-
from __future__ import annotations
|
|
14
|
-
|
|
15
|
-
import importlib.util
|
|
16
|
-
import subprocess
|
|
17
|
-
import sys
|
|
18
|
-
from pathlib import Path
|
|
19
|
-
from types import ModuleType
|
|
20
|
-
|
|
21
|
-
import pytest
|
|
22
|
-
|
|
23
|
-
_SCRIPTS_DIRECTORY = Path(__file__).resolve().parent
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def _load_module() -> ModuleType:
|
|
27
|
-
if str(_SCRIPTS_DIRECTORY) not in sys.path:
|
|
28
|
-
sys.path.insert(0, str(_SCRIPTS_DIRECTORY))
|
|
29
|
-
module_path = _SCRIPTS_DIRECTORY / "append_note.py"
|
|
30
|
-
spec = importlib.util.spec_from_file_location("append_note", module_path)
|
|
31
|
-
assert spec is not None
|
|
32
|
-
assert spec.loader is not None
|
|
33
|
-
module = importlib.util.module_from_spec(spec)
|
|
34
|
-
spec.loader.exec_module(module)
|
|
35
|
-
return module
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
append_note_module = _load_module()
|
|
39
|
-
HEADING_BY_SLUG = append_note_module.HEADING_BY_SLUG
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def test_should_build_skeleton_with_every_section_slug() -> None:
|
|
43
|
-
skeleton = append_note_module._build_skeleton()
|
|
44
|
-
|
|
45
|
-
for each_slug, each_heading in HEADING_BY_SLUG.items():
|
|
46
|
-
assert f'<section id="{each_slug}">' in skeleton
|
|
47
|
-
assert f"<h2>{each_heading}</h2>" in skeleton
|
|
48
|
-
assert skeleton.count("<ul></ul>") == len(HEADING_BY_SLUG)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def test_should_create_file_with_skeleton_on_first_ensure(tmp_path: Path) -> None:
|
|
52
|
-
target = tmp_path / "subdir" / "implementation-notes.html"
|
|
53
|
-
|
|
54
|
-
document = append_note_module._ensure_file(target)
|
|
55
|
-
|
|
56
|
-
assert target.exists()
|
|
57
|
-
assert document == target.read_text(encoding="utf-8")
|
|
58
|
-
assert '<section id="decisions">' in document
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def test_should_return_existing_content_on_subsequent_ensure(tmp_path: Path) -> None:
|
|
62
|
-
target = tmp_path / "notes.html"
|
|
63
|
-
custom_content = "<!doctype html><html><body>existing</body></html>\n"
|
|
64
|
-
target.write_text(custom_content, encoding="utf-8")
|
|
65
|
-
|
|
66
|
-
returned = append_note_module._ensure_file(target)
|
|
67
|
-
|
|
68
|
-
assert returned == custom_content
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def test_should_escape_html_metacharacters_in_about_and_note() -> None:
|
|
72
|
-
entry = append_note_module._render_entry("a<b & c>d", "<script>x</script>")
|
|
73
|
-
|
|
74
|
-
assert "<script>" not in entry
|
|
75
|
-
assert "<script>" in entry
|
|
76
|
-
assert "a<b & c>d" in entry
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
def test_should_put_first_entry_on_its_own_line_inside_empty_ul() -> None:
|
|
80
|
-
skeleton = append_note_module._build_skeleton()
|
|
81
|
-
entry = append_note_module._render_entry("First", "alpha")
|
|
82
|
-
|
|
83
|
-
after_first = append_note_module._insert_entry(skeleton, "decisions", entry)
|
|
84
|
-
|
|
85
|
-
assert "<ul> <li>" not in after_first
|
|
86
|
-
assert "<ul>\n <li>" in after_first
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def test_should_keep_uniform_six_space_indent_across_multiple_entries() -> None:
|
|
90
|
-
skeleton = append_note_module._build_skeleton()
|
|
91
|
-
first_entry = append_note_module._render_entry("First", "alpha")
|
|
92
|
-
second_entry = append_note_module._render_entry("Second", "beta")
|
|
93
|
-
|
|
94
|
-
after_first = append_note_module._insert_entry(skeleton, "decisions", first_entry)
|
|
95
|
-
after_second = append_note_module._insert_entry(after_first, "decisions", second_entry)
|
|
96
|
-
|
|
97
|
-
decisions_section_start = after_second.index('<section id="decisions">')
|
|
98
|
-
decisions_section_end = after_second.index("</section>", decisions_section_start)
|
|
99
|
-
decisions_section = after_second[decisions_section_start:decisions_section_end]
|
|
100
|
-
|
|
101
|
-
assert " <li>" not in decisions_section
|
|
102
|
-
assert decisions_section.count("\n <li>") == 2
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
def test_should_raise_when_requested_section_is_absent() -> None:
|
|
106
|
-
document_without_section = "<html><body></body></html>\n"
|
|
107
|
-
entry = append_note_module._render_entry("x", "y")
|
|
108
|
-
|
|
109
|
-
with pytest.raises(RuntimeError, match="section 'decisions' not found"):
|
|
110
|
-
append_note_module._insert_entry(document_without_section, "decisions", entry)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
def test_should_raise_when_closing_ul_is_missing() -> None:
|
|
114
|
-
truncated_section = '<section id="decisions">\n <h2>Design decisions</h2>\n <ul>\n </section>\n'
|
|
115
|
-
entry = append_note_module._render_entry("x", "y")
|
|
116
|
-
|
|
117
|
-
with pytest.raises(RuntimeError, match="missing its closing </ul>"):
|
|
118
|
-
append_note_module._insert_entry(truncated_section, "decisions", entry)
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
def test_should_not_borrow_closing_ul_from_a_later_section() -> None:
|
|
122
|
-
malformed_first_with_intact_second = (
|
|
123
|
-
'<section id="decisions">\n'
|
|
124
|
-
' <h2>Design decisions</h2>\n'
|
|
125
|
-
' <ul>\n'
|
|
126
|
-
' </section>\n'
|
|
127
|
-
' <section id="deviations">\n'
|
|
128
|
-
' <h2>Deviations</h2>\n'
|
|
129
|
-
' <ul></ul>\n'
|
|
130
|
-
' </section>\n'
|
|
131
|
-
)
|
|
132
|
-
entry = append_note_module._render_entry("x", "y")
|
|
133
|
-
|
|
134
|
-
with pytest.raises(RuntimeError, match="missing its closing </ul>"):
|
|
135
|
-
append_note_module._insert_entry(malformed_first_with_intact_second, "decisions", entry)
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
def test_should_raise_when_closing_section_is_missing() -> None:
|
|
139
|
-
section_without_close = '<section id="decisions">\n <h2>Design decisions</h2>\n <ul></ul>\n'
|
|
140
|
-
entry = append_note_module._render_entry("x", "y")
|
|
141
|
-
|
|
142
|
-
with pytest.raises(RuntimeError, match="missing its closing </section>"):
|
|
143
|
-
append_note_module._insert_entry(section_without_close, "decisions", entry)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
def test_should_append_through_cli_against_real_file(tmp_path: Path) -> None:
|
|
147
|
-
target = tmp_path / "notes.html"
|
|
148
|
-
script_path = _SCRIPTS_DIRECTORY / "append_note.py"
|
|
149
|
-
|
|
150
|
-
first_run = subprocess.run(
|
|
151
|
-
[
|
|
152
|
-
sys.executable,
|
|
153
|
-
str(script_path),
|
|
154
|
-
"--section",
|
|
155
|
-
"decisions",
|
|
156
|
-
"--about",
|
|
157
|
-
"First",
|
|
158
|
-
"--note",
|
|
159
|
-
"alpha",
|
|
160
|
-
"--file",
|
|
161
|
-
str(target),
|
|
162
|
-
],
|
|
163
|
-
cwd=str(_SCRIPTS_DIRECTORY),
|
|
164
|
-
capture_output=True,
|
|
165
|
-
text=True,
|
|
166
|
-
check=False,
|
|
167
|
-
)
|
|
168
|
-
second_run = subprocess.run(
|
|
169
|
-
[
|
|
170
|
-
sys.executable,
|
|
171
|
-
str(script_path),
|
|
172
|
-
"--section",
|
|
173
|
-
"questions",
|
|
174
|
-
"--about",
|
|
175
|
-
"Q1",
|
|
176
|
-
"--note",
|
|
177
|
-
"<beta & gamma>",
|
|
178
|
-
"--file",
|
|
179
|
-
str(target),
|
|
180
|
-
],
|
|
181
|
-
cwd=str(_SCRIPTS_DIRECTORY),
|
|
182
|
-
capture_output=True,
|
|
183
|
-
text=True,
|
|
184
|
-
check=False,
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
assert first_run.returncode == 0, first_run.stderr
|
|
188
|
-
assert second_run.returncode == 0, second_run.stderr
|
|
189
|
-
output = target.read_text(encoding="utf-8")
|
|
190
|
-
assert "<li><strong>First:</strong> alpha</li>" in output
|
|
191
|
-
assert "<li><strong>Q1:</strong> <beta & gamma></li>" in output
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
# log-audit
|
|
2
|
-
|
|
3
|
-
Reads this repository's own logs, finds recurring errors and timing regressions, and turns each real pattern into a tracked fix. Triggered by `/log-audit`, `audit the logs`, `what keeps failing`, or `what's getting slower`.
|
|
4
|
-
|
|
5
|
-
## Purpose
|
|
6
|
-
|
|
7
|
-
The skill runs as a background agent on a recurring schedule. Each cycle it reads the hook block log and the diagnostic extractor pipeline, clusters recurring errors and timing regressions, opens a grouped draft fix pull request or a tracked optimization issue per finding, and mines the defects Copilot and Bugbot keep catching into skill-edit proposals. Cycle state lives under `~/.claude/runtime/log-audit/`, so a restart resumes the same run.
|
|
8
|
-
|
|
9
|
-
## Key files
|
|
10
|
-
|
|
11
|
-
| File | Purpose |
|
|
12
|
-
|---|---|
|
|
13
|
-
| `SKILL.md` | Full instructions: the cycle steps, the three scripts and how to pipe them, the log sources in and out of scope, finding-filing rules, reviewer mining, cycle state, and cadence. |
|
|
14
|
-
|
|
15
|
-
## Subdirectories
|
|
16
|
-
|
|
17
|
-
| Directory | Role |
|
|
18
|
-
|---|---|
|
|
19
|
-
| `reference/` | The agent charter — the fixed contract the skill answers to. |
|
|
20
|
-
| `scripts/` | The collect, cluster, and mine scripts and their constants package. |
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: log-audit
|
|
3
|
-
description: >-
|
|
4
|
-
Watches this repo's own logs for patterns worth acting on: clusters recurring
|
|
5
|
-
errors and timing regressions, then opens a grouped fix PR or a tracked
|
|
6
|
-
optimization issue per real finding. Use for /log-audit, 'audit the logs',
|
|
7
|
-
'what keeps failing', or 'what's getting slower'.
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
# log-audit
|
|
11
|
-
|
|
12
|
-
Read the logs this repo writes about itself, find what keeps going wrong or keeps getting slower, and turn each real pattern into a tracked fix. `reference/charter.md` holds the full contract; this file is how to run a cycle.
|
|
13
|
-
|
|
14
|
-
## One cycle
|
|
15
|
-
|
|
16
|
-
1. **Collect.** Run `scripts/collect_log_window.py` to read the recent window of the hook block log into records.
|
|
17
|
-
2. **Cluster.** Pipe those records into `scripts/cluster_recurrences.py` to group them by a normalized signature and rank the loudest first. When timing samples are on hand, the same module flags operations whose recent runs have grown slower than their earlier runs.
|
|
18
|
-
3. **Mine reviewers.** Run `scripts/mine_copilot_findings.py` to sort recent reviewer-bot comments into defect classes and print a skill-edit proposal for each class.
|
|
19
|
-
4. **File findings.** For each real finding, open a grouped fix pull request as a draft, or file a tracked optimization issue for a delay.
|
|
20
|
-
5. **Report.** Write the per-cycle report: delays removed, pull requests opened, skill improvements suggested.
|
|
21
|
-
6. **Re-arm.** Save cycle state and schedule the next cycle.
|
|
22
|
-
|
|
23
|
-
## Scripts
|
|
24
|
-
|
|
25
|
-
| File | What it does |
|
|
26
|
-
|---|---|
|
|
27
|
-
| `scripts/collect_log_window.py` | Tails the JSON-lines hook block log and prints the block records inside a time window as JSON. `--hours` sets the window; `--log-path` overrides the log location. |
|
|
28
|
-
| `scripts/cluster_recurrences.py` | Reads that JSON on stdin, groups records by a normalized message signature, and prints the clusters ranked by recency-weighted count. Its `detect_timing_regressions` flags an operation whose recent runs are slower than its earliest runs. |
|
|
29
|
-
| `scripts/mine_copilot_findings.py` | Reads a repo's reviewer-bot comments through `gh`, sorts them into defect classes, and prints one skill-edit proposal per class, most frequent first. Takes `--repo owner/name`. |
|
|
30
|
-
|
|
31
|
-
Run the first two as a pipeline:
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
python scripts/collect_log_window.py --hours 24 | python scripts/cluster_recurrences.py
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## What it reads
|
|
38
|
-
|
|
39
|
-
In scope:
|
|
40
|
-
|
|
41
|
-
- The hook block log at `~/.claude/logs/hook-blocks.log`, written by `hook_block_logger`.
|
|
42
|
-
- The `hooks/diagnostic/` extractor pipeline. When Neon is set up, read through that pipeline's SQL — the shape of `queries/blocks_by_category.sql` and its siblings against the `hook_events` table, which carries `duration_ms` for timing work. When Neon is not set up, read the flat `hook-blocks.log` directly. Reuse the diagnostic pipeline's helpers; do not hold a second copy.
|
|
43
|
-
|
|
44
|
-
Out of scope: Samsung-automation logs. Read this repo's log surfaces only.
|
|
45
|
-
|
|
46
|
-
## Filing findings
|
|
47
|
-
|
|
48
|
-
- A pull request or optimization issue carries its body in a file passed by path, following the `gh-body-file` rule.
|
|
49
|
-
- Any paginated GitHub read follows the `gh-paginate` rule.
|
|
50
|
-
- Group the related fixes for one finding into a single draft pull request rather than one PR per line.
|
|
51
|
-
|
|
52
|
-
## Reviewer-defect mining
|
|
53
|
-
|
|
54
|
-
`mine_copilot_findings.py` names a skill or rule edit for each defect class the reviewers keep catching — an edit that would block that class at write time rather than at review. These are proposals. A human applies them through review; the agent does not commit them on its own.
|
|
55
|
-
|
|
56
|
-
## Cycle state and restart survival
|
|
57
|
-
|
|
58
|
-
The agent keeps its state in a JSON file under `~/.claude/runtime/log-audit/` — the last window it read, the signatures it already reported, and the open items it filed. At the start of each cycle, read that file; at the end, write it back. Because the state lives in the durable runtime directory rather than the OS temp directory, a restart reads the same file and resumes the same run.
|
|
59
|
-
|
|
60
|
-
## Cadence
|
|
61
|
-
|
|
62
|
-
The agent runs on a recurring schedule following the repository's Scheduled Task Cadence: a sub-hour interval, with a 30-minute default. Re-arm the next cycle with `ScheduleWakeup` for a self-paced loop, or register a cron routine through `/schedule` for a fixed clock cadence.
|
|
63
|
-
|
|
64
|
-
## Per-cycle report
|
|
65
|
-
|
|
66
|
-
Each cycle ends with a short report: the delays removed, the pull requests opened, and the skill improvements suggested.
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# log-audit/reference
|
|
2
|
-
|
|
3
|
-
Reference material for the `log-audit` skill.
|
|
4
|
-
|
|
5
|
-
## Key files
|
|
6
|
-
|
|
7
|
-
| File | Purpose |
|
|
8
|
-
|---|---|
|
|
9
|
-
| `charter.md` | The agent's contract: what it watches (this repo's hook-block log and diagnostic extractor pipeline), what it looks for (recurring errors and timing regressions), what it files per finding (grouped draft fix PR or tracked optimization issue), how it mines reviewer defect patterns into skill-definition proposals, and the per-cycle report it emits. Cycle state lives under `~/.claude/runtime/log-audit/`; the agent runs on a sub-hour cadence. |
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# Log-Audit Agent Charter
|
|
2
|
-
|
|
3
|
-
The contract for the log-audit agent: what it watches, what it looks for, and what it produces each cycle. The skill body (`SKILL.md`) and its scripts carry out this contract; this document is the fixed reference they answer to.
|
|
4
|
-
|
|
5
|
-
## What the agent is
|
|
6
|
-
|
|
7
|
-
A background agent that reads this repository's own log surfaces, finds patterns worth acting on, and turns each real pattern into a tracked fix. It runs on its own without a person driving it and picks up where it left off after a restart.
|
|
8
|
-
|
|
9
|
-
## Cycle state and cadence
|
|
10
|
-
|
|
11
|
-
The agent keeps its own state on disk under `~/.claude/runtime/log-audit/`. This directory holds durable cycle state — the last window it read, the signatures it already reported, and the open items it filed — so a restart resumes the same run rather than starting over. The OS temp directory is not a home for this state, because temp files can be cleared between sessions.
|
|
12
|
-
|
|
13
|
-
The agent runs on a recurring schedule. It follows the repository's Scheduled Task Cadence: a sub-hour interval, with a 30-minute default.
|
|
14
|
-
|
|
15
|
-
## Log sources it reads
|
|
16
|
-
|
|
17
|
-
In scope:
|
|
18
|
-
|
|
19
|
-
- The hook block log at `~/.claude/logs/hook-blocks.log`, written by `hook_block_logger`. Each line is one JSON record naming the hook that blocked, the event, the reason, the tool, and a short input excerpt.
|
|
20
|
-
- The `hooks/diagnostic/` extractor pipeline. When Neon is configured, the agent reads through the pipeline's SQL — the shape of `queries/blocks_by_category.sql` and its siblings against the `hook_events` table, which carries `duration_ms` for timing work. When Neon is not configured, the agent reads the flat `hook-blocks.log` directly. It reuses the diagnostic pipeline's helpers rather than holding a second copy of them.
|
|
21
|
-
|
|
22
|
-
Out of scope:
|
|
23
|
-
|
|
24
|
-
- Samsung-automation logs. The agent reads this repository's log surfaces only.
|
|
25
|
-
|
|
26
|
-
## What it looks for
|
|
27
|
-
|
|
28
|
-
Two kinds of pattern:
|
|
29
|
-
|
|
30
|
-
- Recurring errors. The same failure showing up again and again. The agent groups log records by a normalized message signature — the message with its digits, paths, and hashes stripped — so records that differ only in those details fall into one cluster. It ranks clusters by count weighted toward recent activity.
|
|
31
|
-
- Timing regressions. The same operation taking longer over time. When a repeated operation's duration climbs across cycles, the agent flags it as an unnecessary delay, separate from any error.
|
|
32
|
-
|
|
33
|
-
## What it does per finding
|
|
34
|
-
|
|
35
|
-
For each real finding, the agent takes one of two tracked actions:
|
|
36
|
-
|
|
37
|
-
- Opens a grouped fix pull request as a draft, gathering the related fixes into one branch.
|
|
38
|
-
- Files a tracked optimization issue when the finding is a delay to chase rather than a fix to write.
|
|
39
|
-
|
|
40
|
-
Both paths carry their body in a file passed by path, following the `gh-body-file` rule, and any paginated GitHub read follows the `gh-paginate` rule.
|
|
41
|
-
|
|
42
|
-
## Reviewer-defect mining
|
|
43
|
-
|
|
44
|
-
The agent also reads the defect patterns that Copilot and Bugbot catch again and again across recent pull requests. It clusters those comments into defect classes and proposes concrete edits to the skill definitions that would block each class upstream, at the point of writing, rather than at review. These are proposals: they land through review, not by the agent applying them on its own.
|
|
45
|
-
|
|
46
|
-
## Per-cycle report
|
|
47
|
-
|
|
48
|
-
Each cycle ends with a short report covering:
|
|
49
|
-
|
|
50
|
-
- Delays removed.
|
|
51
|
-
- Pull requests opened.
|
|
52
|
-
- Skill improvements suggested.
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# log-audit/scripts
|
|
2
|
-
|
|
3
|
-
The collect, cluster, and mine scripts for the `log-audit` skill, plus their constants package.
|
|
4
|
-
|
|
5
|
-
## Files
|
|
6
|
-
|
|
7
|
-
| File | Purpose |
|
|
8
|
-
|---|---|
|
|
9
|
-
| `collect_log_window.py` | Tails the JSON-lines hook block log and prints the block records inside a time window as JSON. |
|
|
10
|
-
| `test_collect_log_window.py` | Tests for `collect_log_window.py`. |
|
|
11
|
-
| `cluster_recurrences.py` | Groups block records by a normalized signature, ranks them by recency-weighted count, and flags timing regressions. |
|
|
12
|
-
| `test_cluster_recurrences.py` | Tests for `cluster_recurrences.py`. |
|
|
13
|
-
| `mine_copilot_findings.py` | Sorts reviewer-bot comments into defect classes and prints one skill-edit proposal per class. |
|
|
14
|
-
| `test_mine_copilot_findings.py` | Tests for `mine_copilot_findings.py`. |
|
|
15
|
-
|
|
16
|
-
## Subdirectories
|
|
17
|
-
|
|
18
|
-
| Directory | Role |
|
|
19
|
-
|---|---|
|
|
20
|
-
| `log_audit_constants/` | Named constants imported by the three scripts. |
|
|
21
|
-
|
|
22
|
-
## Running
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
python collect_log_window.py --hours 24 | python cluster_recurrences.py
|
|
26
|
-
python mine_copilot_findings.py --repo owner/name
|
|
27
|
-
```
|