aboutsummaryrefslogtreecommitdiff
path: root/Makefile
Commit message (Collapse)AuthorAgeFilesLines
* feat(install): adopt the statusline script into the managed setCraig Jennings3 days1-1/+1
| | | | | | An archsetup session added a statusLine entry to the tracked settings.json on 2026-06-11 (Craig's request), pointing at ~/.claude/statusline-command.sh, but the script itself lived outside the repo on one machine. This commits the settings entry and brings the script into .claude/, linked by make install like the rest of the config, so it reaches every machine on the next session. Two fixes over the original: uname -n instead of hostname (Arch doesn't ship hostname by default, so the host rendered empty with stderr noise), and the tilde replacement is escaped (unquoted, bash expands the replacement ~ straight back to $HOME, which defeated the abbreviation). scripts/tests/statusline-command.bats covers the format, branch handling, and the no-stderr contract.
* fix(install): link default hooks in make installCraig Jennings3 days1-2/+15
| | | | | | session-clear-resume.sh shipped 2026-06-02 with its settings.json entry, but make install didn't cover hooks and nothing re-ran install-hooks, so the symlink only existed on machines that had linked it by hand. Everywhere else the hook errored silently on every /clear. make install now links DEFAULT_HOOKS alongside skills, rules, config, and bin scripts, so the startup workflow's install step propagates new hooks machine-wide. Opt-in hooks stay manual. scripts/tests/install-hooks-link.bats covers the new section. The SessionStart-on-clear todo task closes with this: the hook feature already existed, and the gap was distribution.
* feat(typescript): add coverage-summary to the TypeScript bundleCraig Jennings14 days1-0/+9
| | | | | | | | | | Last language in the coverage-summary fan-out, after Elisp, Python, and Go. Same kernel: count every source file on disk that's absent from the coverage report as 0% and weight the project number by file, so an untested file stays visible instead of being averaged away. The script at languages/typescript/claude/scripts/coverage-summary.js parses an Istanbul json-summary report (the coverage-summary.json that c8, Vitest, and Jest all emit), takes per-file statements covered over total, and reports a file-weighted number plus the missing files. It walks the source dir for .ts/.js, skipping test files, declarations, and node_modules. Node built-ins only, so it runs via node with no install, and it doesn't reimplement the per-file table nyc already prints. Tests are black-box, run with node's own test runner: a temp tree plus a json-summary report, the script invoked via node, output asserted. They cover missing-file detection, all-tracked, test-file and node_modules exclusion, and the missing-report error. make test gained a node --test discovery path for languages/*/tests, guarded so environments without Node skip it cleanly. As with Python, the TypeScript bundle had no gitignore-add.txt, which would have left the script un-gitignored on install, so I added one. This finishes the fan-out: coverage-summary now ships in all four bundles, each parsing its own tool's report behind the same file-weighted, missing-as-0% kernel. I proved the Go and TypeScript scripts by running them (Go against a live profile, TS against a synthetic report and the CLI). Python and TypeScript weren't run against a live coverage tool, since neither coverage.py nor nyc is installed here, so the first adopter of each should check against a real report.
* feat(go): add coverage-summary as a Go bundle coverage sliceCraig Jennings14 days1-0/+9
| | | | | | | | | | Third language in the coverage-summary fan-out, after Elisp and Python. Same kernel: count every source file on disk that's absent from the coverage profile as 0% and weight the project number by file, so an untested file stays visible instead of being averaged away. The script at languages/go/claude/scripts/coverage-summary.go parses a cover.out profile, maps each import-path-qualified entry back to an on-disk relative path using the module path from go.mod, and reports a file-weighted number plus the missing files. It's standard library only, so it runs anywhere via go run, and it doesn't reimplement the per-function table that go tool cover -func already prints. I proved it against a real go test -coverprofile run, not just a synthetic fixture, since the Go toolchain is installed here. Two findings to flag. Modern go test ./... already lists every module package in the profile at 0% even when untested, so for in-module code the missing-file list is usually empty. The detection earns its keep on build-tagged files and dirs outside ./.... And this is a coverage-only slice of a Go bundle that doesn't otherwise exist yet: there's no go.md rule file, so sync-language-bundle.sh can't fingerprint it (detection keys on a bundle's own .claude/rules). The script installs via make install-lang LANG=go but won't be sync-maintained until the Go bundle gets real rules and a CLAUDE.md. Building that out is the natural companion task. Tests are black-box: a Go test in its own throwaway module runs the script via go run against temp fixtures and checks output, so the shipped script dir stays test-free. They cover missing-file detection, all-tracked, _test.go exclusion, and the missing-report error. make test gained a go test discovery path for languages/*/tests, guarded so environments without Go skip it cleanly.
* feat(python): add coverage-summary to the Python bundleCraig Jennings14 days1-0/+5
| | | | | | | | | | Second language in the coverage-summary fan-out, after the Elisp pilot. Same kernel: a module no test imports never appears in coverage.py's report, so a line-weighted total skips it silently and the suite looks healthier than it is. This counts every source file on disk that's absent from the report as 0% and weights the project number by file, so untested modules stay visible. The script at languages/python/claude/scripts/coverage-summary.py parses coverage.py's JSON (files[path].summary.covered_lines / num_statements), resolves report paths against the report's directory since coverage records them relative to where it ran, and recurses the source dir for *.py. Unlike the Elisp version it doesn't print a per-file table, because coverage.py's own coverage report already does. The script adds the missing-file accounting that report lacks. It uses only the standard library, parsing the report rather than importing coverage. The Python run confirmed the plumbing from the pilot is genuinely generic. install-lang and sync deliver the script and the project-owned coverage-makefile.txt with no Python-specific code. The one gap I had to close: the Python bundle shipped without a gitignore-add.txt, so the .claude/ footprint wasn't ignored and the script would have been committable. Added one mirroring the Elisp footprint plus Python artifacts (__pycache__, .coverage, coverage.json). make test gained a languages/*/tests/test_*.py discovery path alongside the existing Elisp ERT one. Tests: 12 pytest covering the parser, the file-weighted number, and the missing-file detection including subpackage recursion, plus an install-lang check that the script lands in the gitignored footprint. I proved it against a report matching coverage.py's documented schema and the CLI end to end, but not against a live coverage json run, because coverage.py isn't installed in this repo's env. The first project to adopt it should sanity-check against a real report.
* feat(elisp): add coverage-summary to the Elisp bundle with missing-file ↵Craig Jennings14 days1-0/+5
| | | | | | | | | | | | | | detection A line-weighted coverage total has a blind spot: a module no test loads never shows up in the SimpleCov report, so it can't drag the number down. The suite looks healthier than it is. This adds a summary that counts every source file on disk against the report and treats an absent file as 0%, weighting the project number by file instead of by line so untested modules stay visible. The script ships at languages/elisp/claude/scripts/coverage-summary.el, self-contained on stock Emacs (just the built-in json). It parses the undercover SimpleCov shape directly rather than depending on the editor's coverage engine, so it runs anywhere the bundle lands. I proved it against a real 103-file report: 93 tracked, 27 untested modules surfaced, project number 66.4%. Delivery follows the bundle convention. The script lives under the gitignored .claude/ footprint and gets auto-fixed on drift by sync-language-bundle.sh, which I made generic for any claude/scripts/* rather than coverage-specific. The Makefile targets ship as a project-owned fragment (languages/elisp/coverage-makefile.txt) that install-lang.sh seeds at the project root and sync drops into .ai/inbox/ when that convention exists. The bundle never edits the project's own Makefile. Tests: 12 ERT for the kernel (Normal/Boundary/Error per function), wired into make test via a new languages/*/tests/ discovery path, plus bats for the sync auto-fix and the inbox-drop guards. This is the Elisp pilot. The pattern is proven, so fanning out to Python, Go, and TypeScript is now a follow-up. Each one needs only its own parser and fragment. The plumbing is already generic.
* feat(signal): page-signal CLI wrapper + workflows + cross-project broadcast ↵Craig Jennings2026-05-291-15/+19
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | helper Three coupled additions ship together. claude-templates/bin/page-signal is a bash wrapper around signal-cli send. It defaults to --note-to-self for safety. The wrapper supports --file for attachments, --to <+number> for outbound (explicit per call, no defaults, no batch), --quiet, and --json. Exit codes: 0 sent, 1 signal-cli failure, 2 usage error, 3 signal-cli not installed. claude-templates/.ai/workflows/page-signal.org carries the discrimination rules and safety rails. When desktop notify covers it, don't reach for Signal. Long-running task completion is the canonical case. Outbound to other contacts requires explicit Craig instruction per send. A known-limitation note covers the current notification gap. signal-cli registered on Craig's primary number means messages don't fire notifications until the pending Google Voice registration lands. claude-templates/.ai/workflows/cross-project-broadcast.org and its helper cross-project-broadcast.py fan out a single message file to every AI project's inbox in one operation. Discovery is fingerprint-based: any directory under ~/code, ~/projects, ~/.emacs.d with both .ai/protocols.org and a top-level inbox/ is broadcastable. Senders are auto-excluded. Verified discovery against 23 broadcastable targets. Makefile's install target gains a general bin/ loop. The previous version hardcoded bin/ai. The new version iterates over every executable under claude-templates/bin/ and symlinks each into ~/.local/bin/. install-hooks (existing Claude hook installer) is unchanged. install-githooks (sync-check pre-commit hook setup, added earlier today) is unchanged. The bin/ loop now picks up bin/page-signal automatically. INDEX entries for both new workflows landed under Tools and meta. No bats tests on the new scripts. page-signal was smoke-tested with a live send. The send succeeded. The notification gap is covered by the workflow's known-limitation note. cross-project-broadcast.py was smoke-tested via --list against the live project set. Tests can be added when the broadcast pattern proves out across multiple use cases.
* feat(mcp): add uninstall + --check + README section for MCP pipelineCraig Jennings2026-05-281-0/+6
| | | | | | | | | | | | | | | | | | | | | | | | | | | Three coupled additions close the MCP pipeline thread. mcp/install.py grew --uninstall and --check modes via argparse. The default install behavior is unchanged. --uninstall iterates over servers.json and runs `claude mcp remove <name> -s user` for each, skipping anything not registered. Idempotent. --check is the dry-run drift report. For each server, classify as ok (in both servers.json and `claude mcp list`), MISSING (configured but not registered), or EXTRA (registered but not in servers.json). Exit non-zero only on MISSING since EXTRA entries are often deliberate (the claude.ai web servers register out-of-band). Smoke test against the live config: 9 ok, 0 missing, 3 EXTRA, exit 0. Two new Makefile targets: - make uninstall-mcp invokes the --uninstall mode. - make check-mcp invokes the --check mode. README.org gained an MCP section under Two install modes covering all three targets, the OAuth-token-on-disk story, and a pointer to mcp/README.org for the full pipeline. Closes TODO #7 (uninstall + --check) and TODO #8 (README MCP section).
* feat(status): add `make status` for compact health summaryCraig Jennings2026-05-281-0/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | scripts/status.sh prints a six-line summary composing existing checks: - audit + doctor (one call, since audit.sh runs doctor internally) - canonical/mirror sync state via sync-check.sh - open todo count under * <Project> Open Work - inbox count (excluding .gitkeep and PROCESSED- prefixes) - git working-tree state with ahead/behind upstream Sample output: rulesets status — 2026-05-28 09:13 CDT audit Summary: 41 ok, 0 warnings, 2 failures sync canonical = mirror todo 22 open inbox 1 unprocessed git main dirty — in sync with origin/main The script adds no new logic beyond formatting. `make status` is the entry point. The scope here is limited per the triage disposition for codex item #12. The rest of #12 was rejected. `make sync` duplicates the existing sync flow, `make health` wraps existing checks without adding signal, `make bootstrap-project` duplicates `install-ai` + `install-lang`.
* feat(sync-check): canonical/mirror drift detection + pre-commit hookCraig Jennings2026-05-281-0/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | scripts/sync-check.sh diffs claude-templates/.ai/{protocols.org, workflows,scripts} against the .ai/ mirror. Exits 0 when clean, 1 with a diff report on drift, 2 outside a rulesets-shaped repo or git checkout. --fix mode rsyncs canonical -> mirror and re-checks, then prompts to re-stage. githooks/pre-commit wraps the script. Commits abort on drift so the issue surfaces at publish time, not at the next session's startup rsync. Two new Makefile targets: - make sync-check [FIX=1] runs the script (FIX=1 passes --fix through). - make install-githooks sets core.hooksPath=githooks (idempotent). scripts/tests/sync-check.bats holds 8 tests covering clean, drift-per-path, --fix, extra-file removal, missing canonical, and outside-git. All eight pass. This catches the exact drift I had to fix manually during this morning's audit pass. The mirror's open-tasks.org PROPERTIES drawer sat below a sub-heading because the mirror commit was older than canonical.
* feat(make): add an interactive remove target with fzfCraig Jennings2026-05-221-1/+4
| | | | | | make remove is the granular counterpart to make uninstall, which removes everything. remove.sh lists every rulesets-managed symlink under ~/.claude/ — only links whose target resolves into the repo, so foreign symlinks are left alone — pipes them through fzf --multi, and rm's the picked links. The repo's own files stay put, and make install re-creates anything removed. It's split into --list and --remove-selected modes so the logic is testable without fzf. 5 bats cases cover the listing, the foreign-link exclusion, removal, report-and-continue on a missing target, and the empty no-op. The removal loop runs without set -e and without rm -f, so a vanished target reports visibly and the rest still process. shellcheck clean, make test green.
* feat: split team publishing rules into an installable overlayCraig Jennings2026-05-221-0/+21
| | | | | | | | | | | | The global commits.md carried DeepSat-specific publishing steps — Linear ticket-state moves, the Slack notification protocol with its channel ID and engineer names, the deepsat.ghe.com host, the team merge norm. Those are symlinked into every project on the machine, so they sat as dead weight in personal repos and risked misfiring where there's no Linear ticket to move or Slack mpdm to ping. I split them out. commits.md keeps the universal skeleton (identity, attribution, commit format, the review-and-publish gate, verification) and replaces the team steps with seams: "run the project's publishing overlay here if it defines one," the same pattern startup.org uses for startup-extras. A project with no overlay runs the complete flow, just without ticket and chat integration. The DeepSat specifics move to teams/deepsat/claude/rules/publishing.md. That file is not a global rule — install-team.sh copies it into one project's .claude/rules/ (make install-team TEAM=deepsat PROJECT=...), keyed on the PROJECT argument, so only the named project gets it. Location decides distribution: claude-rules/ is the global-symlink set, teams/ is targeted-copy, so the overlay reaches DeepSat and nowhere else. The startup freshness check (sync-language-bundle.sh) now covers team overlays alongside language bundles: a process_bundle function handles both, with a team syncing only its own rule (no generic rules, hooks, or settings — those belong to a language bundle). A drifted overlay rule auto-fixes from canonical at the project's next startup, the same mechanism language bundles already ride. Tested: 3 new bats cases (team overlay clean / drifted-and-fixed / does-not-pull-generic-rules) on top of the 11 existing; install-team + sync verified end-to-end against a temp project. make test green, shellcheck clean.
* feat(hooks): scan file-backed messages and harden rm parsingCraig Jennings2026-05-221-0/+1
| | | | | | | | | | Two audit gaps in the confirmation hooks, plus the test harness they were missing. The git-commit and gh-pr-create hooks scanned for AI attribution but only saw inline messages. A commit made with -F/--file or a PR made with --body-file slipped through, since the hook stored a placeholder instead of the file's text, and the publish flow uses -F constantly. A new read_referenced_file helper in _common.py reads the referenced local file (missing, oversized, or non-UTF-8 returns None, which means "couldn't inspect" and never "clean"), so attribution scanning now sees the real committed and posted text. An unreadable file falls through to the existing ask-anyway path. destructive-bash-confirm.py parsed rm flags by splitting on whitespace, which mangled quoted paths and missed flag variants. detect_rm_rf now tokenizes with shlex, so quoted or spaced paths and combined, separate, or reordered flags all parse. It fails toward asking (a sentinel that still fires the modal) on unbalanced quotes, or when a forced recursive rm sits alongside a pipeline, compound command, substitution, or redirect, since target attribution isn't trustworthy there. The supported and unsupported shell constructs are documented in the docstrings. These hooks had no tests and weren't in make test. Added a pytest harness under hooks/tests (an importlib-by-path loader, since the hook filenames are hyphenated) with 54 tests across the three hooks and the shared helper, and wired hooks/tests into make test. Full suite green.
* test(scripts): add task-review-staleness.sh + bats harnessCraig Jennings2026-05-201-1/+1
| | | | | | | | First component of the daily task-review habit from docs/design/task-review.org. The staleness count is the shared primitive both the wrap-up health check (threshold 30) and the startup reminder (threshold 7) call, so it lives in one tested script rather than being reimplemented in each workflow. The script counts top-level todo.org tasks whose review has gone stale: depth-2 headings with a TODO/DOING/VERIFY keyword and an [#A]/[#B]/[#C] cookie, where LAST_REVIEWED is missing, unparseable, or older than the threshold. Age uses a strict greater-than, so a task reviewed exactly N days ago is still fresh. Today normalizes to local midnight before the diff, and the day count rounds to the nearest day, so a DST hour can't push a boundary task across the line. Twelve bats cases cover the normal, boundary, and error categories. Dates are generated relative to the current date rather than hardcoded. The script path resolves as the sibling-of-parent of the test file, so the suite runs identically from the canonical claude-templates tree and the rsync'd project mirror. Makefile test target now globs .ai/scripts/tests for bats alongside scripts/tests.
* test(scripts): add bats harness for audit + install-ai edge casesCraig Jennings2026-05-151-1/+6
| | | | | | | | Adds scripts/tests/audit.bats (6 tests) and scripts/tests/install-ai.bats (5 tests) covering the three destructive edge cases that the fold-epic test plan deferred yesterday: audit --apply --force clobbering a tracked dirty .ai/, audit's loop continuing past a missing-.ai/ project, and install-ai's interactive fzf-pick form. The first two go alongside happy-path sanity (clean sweep, drift detection, --apply convergence, dirty-skip); install-ai gets happy-path with explicit PROJECT, --track gitkeep stubs, refusal on existing .ai/, and notes.org placeholder substitution. Strategy: redirect HOME to a per-test mktemp dir, scaffold synthetic project trees under HOME/code/, and run the real scripts against them. The canonical source stays the real one (resolved relative to each script's own location), so tests exercise the production rsync paths without copying canonical content. Use PATH stubs for fzf and find to cover the interactive and race-condition edges. Makefile test: target extended with a bats stanza; description updated to "Run all test suites (pytest + ERT + bats)". make test now runs 352 green (296 pytest + 22 lint-org ERT + 23 todo-cleanup ERT + 6 audit bats + 5 install-ai bats), up from 341.
* feat(make): add catchup-machine target for cross-machine .ai/ syncCraig Jennings2026-05-151-0/+3
| | | | | | | | scripts/catchup-machine.sh runs the four steps that bring a machine in sync with rulesets canonical: git pull, make install (symlink refresh), make audit APPLY=1 (rsync .ai/ across all projects), and make doctor (verify). Idempotent, safe to re-run any time. Built for the post-fold ratio migration but applies generally: after a fresh rulesets clone on a new machine, or whenever the canonical source has advanced since last sync. Handles dirty working trees by skipping the pull and surfacing a warning; user commits or stashes before re-running.
* feat(make): add install-ai target for bootstrapping .ai/ in fresh projectsCraig Jennings2026-05-151-0/+6
| | | | | | | | scripts/install-ai.sh copies canonical .ai/ content from claude-templates/ into a fresh project. Rsyncs protocols.org, workflows/, scripts/, someday-maybe.org as-is; templates notes.org with project-name and date placeholders substituted; creates empty sessions/, references/, retrospectives/ dirs. Two tracking modes: TRACK=1 adds .gitkeep files inside otherwise-empty dirs so they survive in git history; GITIGNORE=1 appends .ai/ to the project's .gitignore so session records stay local. Prompts interactively if neither flag is set. Refuses if PROJECT/.ai/ already exists with a message pointing to `make audit APPLY=1` for sync of existing installs. Without a PROJECT argument, fzf-picks from ~/code/* + ~/projects/* git checkouts that don't already have .ai/.
* feat(make): add audit target for cross-project .ai/ drift detectionCraig Jennings2026-05-151-0/+6
| | | | | | | | scripts/audit.sh walks every .ai/-using project under ~/code/, ~/projects/, and ~/.emacs.d/, compares each .ai/ against the canonical source at claude-templates/.ai/, and reports drift per project. Default mode is report-only; APPLY=1 rsyncs detected drift into each project (no auto-commit). FORCE=1 also rsyncs into projects with uncommitted .ai/ changes (default: skip with a warning). Uses diff -rq for content comparison rather than rsync --itemize-changes to avoid false positives on attribute-only drift (mtime, permissions). Skips the rulesets repo itself, the in-repo canonical source, and the legacy standalone ~/projects/claude-templates/ during the fold transition. Output mirrors make doctor: per-project ok/drift/applied/skipped/FAIL lines, summary tally, exit 0 when all ok. Runs make doctor as the final check by default; NO_DOCTOR=1 skips.
* chore(make): fold bin/ai launcher install into rulesetsCraig Jennings2026-05-151-0/+29
| | | | | | The ai launcher's install/uninstall logic lived in claude-templates/Makefile when claude-templates was a separate repo. After the fold, that Makefile still works locally but rulesets' make install is the single entry point. Add ai-launcher targets to rulesets/Makefile so `make install` covers it alongside skills, rules, commands, and Claude config. Install detects an existing symlink pointing at a stale source (e.g. ~/projects/claude-templates/bin/ai from before the fold) and relinks to the new canonical path under ~/code/rulesets/claude-templates/bin/ai.
* build(deps): install pdftools so every project can edit PDFsCraig Jennings2026-05-131-1/+20
| | | | | | poppler (pdftoppm/pdftotext) plus a dedicated Python venv at ~/.local/venvs/pdftools with pypdf, reportlab, and pillow. Every project session can now stamp checkboxes, dates, and text overlays onto flattened PDFs through that venv, without each project re-wiring the toolchain. The package name for poppler diverges across distros (poppler-utils on Debian/Ubuntu, poppler on Arch and Homebrew), so the install branch handles each manager inline rather than going through install_pkg. PDFTOOLS_VENV is overridable via env if a machine needs a different path.
* feat(todo-cleanup): add --archive-done mode with ERT test suiteCraig Jennings2026-05-111-1/+9
| | | | | | | | --archive-done moves every level-2 subtree whose TODO state is DONE or CANCELLED out of the "Open Work" section into the "Resolved" section of the same org file, subtree intact. Sections match on a unique level-1 heading containing "Open Work" (case-insensitive) and one containing "Resolved"; a missing or ambiguous section skips the file with a message rather than crashing. Only direct level-2 children move. A DONE entry nested under an open parent stays put. Opt-in, never run by default, doesn't also run the hygiene passes; --check previews without writing. The CLI dispatch moved into tc-main behind a guard so the new ERT suite can require the file without firing it. Hygiene mode is unchanged. 13 ERT cases (the repo's first elisp tests) cover the move and the stay-put cases, EOF with no final newline, missing or ambiguous sections, lowercase headings, idempotency, and --check. tests/fixtures/todo-sample.org is the synthetic sample, and the Makefile test target now runs the ERT suites alongside pytest.
* feat(scripts): add readability tool + pre-warm textstat in depsCraig Jennings2026-05-081-0/+7
| | | | | | | | Adds scripts/readability — a Python tool that prints standard readability metrics (Flesch Reading Ease, Flesch-Kincaid Grade, Gunning Fog, SMOG, Coleman-Liau, ARI, Dale-Chall, Linsear-Write) for one input file or as a side-by-side comparison of two. Self-contained via PEP 723 inline metadata: textstat is declared as the script's only dependency, and the `#!/usr/bin/env -S uv run --quiet --script` shebang lets uv resolve it on each invocation. The Makefile `deps` target now also pre-warms textstat in uv's cache so the first interactive run is fast.
* feat(make): add bootstrap target for fresh-machine setupCraig Jennings2026-05-081-0/+9
| | | | Bootstrap chains install, install-hooks, and install-mcp into one command. The three targets stay split so routine re-symlinking stays cheap (no GPG pinentry, no network), but bootstrap gives the fresh-install case one entry point. The gap surfaced on a fresh machine where doctor flagged 4 hook warnings and 8 MCP failures.
* feat(make): add doctor target for ~/.claude drift detectionCraig Jennings2026-05-071-1/+4
| | | | | | | | | | | | =make doctor= scans =~/.claude/= and reports drift against the repo + settings.json. Read-only diagnostic. Eight checks cover skills, rules, default hooks, claude config, settings.json hook references, enabledPlugins, MCP server registrations, and dangling symlinks. Each line prints =ok= / =WARN= / =FAIL= with a final summary. Exit 1 on any FAIL. A sweep last night found =~/.claude/hooks/= didn't exist on this machine even though =settings.json= referenced a PreCompact hook there. Compaction would have silently failed to invoke it. doctor catches that kind of drift in one command instead of relying on a manual look. The MCP drift check reads =~/.claude.json= directly rather than parsing =claude mcp list=. The CLI has no JSON output and runs a per-server health probe (~10s). The JSON file is the user-scope source of truth for registrations and parses in well under a second. I verified by injecting four drift scenarios — removed hook symlink, removed skill symlink, moved-aside plugin data dir, unregistered MCP server. Each produced the expected =FAIL= line and exit 1. After restoring state, doctor came back clean (33 ok). Bundling four other improvement TODOs from the same sweep — =mcp/README.org=, =make uninstall-mcp= and =mcp/install.py --check=, a README.org section for the MCP install pipeline, and a token-rotation helper for =@a-bonus/google-docs-mcp= OAuth refresh. Plus a stale-bullet note on the existing =make remove= TODO (the bridge symlink it references was removed earlier).
* chore(make): remove unused claude-rules bridge symlinkCraig Jennings2026-05-061-18/+0
| | | | | | The bridge at ~/.claude/skills/claude-rules existed so a SKILL.md could resolve a relative path like ../claude-rules/testing.md from the install layout. No SKILL.md actually uses that pattern. Every reference I grepped — across debug, add-tests, and pairwise-tests — names the rule file by bare filename in prose, which doesn't go through any link. The symlink was defensive scaffolding for a use case that didn't land. The four rule files keep loading via ~/.claude/rules/ unchanged. Claude Code's skill harness was silently ignoring the bridge anyway because the target directory has no SKILL.md, so no behavior moves except that make install stops creating the dead entry. If a future SKILL.md wants deep-linking, the bridge can come back deliberately.
* feat(mcp): add user-scope MCP install pipelineCraig Jennings2026-05-061-1/+6
| | | | | | | | | | I needed a single source of truth for MCP server registration so a fresh machine boots with the full set instead of being rebuilt by hand. install.py decrypts mcp/secrets.env.gpg, expands ${VAR} placeholders in mcp/servers.json, and runs claude mcp add --scope user for anything not already registered. Idempotent. The encrypted bundle carries six values: the Google client id and secret, the Figma API key, the GCP OAuth keys JSON (base64), and the two @a-bonus/google-docs-mcp token caches (personal and work, base64). install.py writes the keys file and the two token files to the paths each package reads at startup, all mode 600. Bundling the Google Docs tokens lets a new machine connect google-docs-personal and google-docs-work without the interactive OAuth flow. Without the cached token, the package falls back to a browser-redirect flow that Claude Code's stdio MCP loader can't drive, so it shows "Failed to connect" until the user runs the npx command manually. Make target: install-mcp. Plaintext secrets and the decrypted keys file are gitignored.
* feat(make): fzf-pick LANG when not set, mirror project pickerCraig Jennings2026-05-061-8/+29
| | | | Add a pick_lang_shell macro that fzf-picks from $(LANGUAGES) when LANG isn't set, mirroring pick_project_shell. Wire it into install-lang and diff so both vars are now optional. Blank $(LANG) when its origin is environment, since LANG is the standard POSIX locale env var and Make would otherwise inherit "en_US.UTF-8" and bypass the picker.
* feat(hooks): make destructive-bash-confirm opt-inCraig Jennings2026-05-061-3/+16
| | | | | | | | | | I added an OPTIN_HOOKS list in the Makefile and excluded those entries from the default install-hooks recipe. destructive-bash-confirm.py is the first opt-in. The recipe now prints the exact ln -s command for each opt-in so users can wire individual ones without consulting docs. uninstall-hooks and list still iterate the full HOOKS list so they keep handling opt-ins that someone has manually linked.
* feat(claude): add claude config and wire it into make installCraig Jennings2026-05-061-7/+64
| | | | | | | | I moved Claude Code's user-level config into this repo so it travels with rulesets across machines instead of being machine-specific. The three pieces are settings.json, .mcp.json, and commands/refactor.md. I extended make install, uninstall, and list to handle the new .claude/ directory. The wildcard for CLAUDE_CONFIG matches both `*.json` and `.*.json` because make's glob skips dotfiles by default. Without the dot variant, .mcp.json wouldn't get picked up. I also added settings.local.json to .gitignore. That file is per-machine by convention and shouldn't ever land in the shared repo.
* chore(build): wildcard SKILLS, claude-rules bridge symlink, link lintCraig Jennings2026-04-261-5/+19
| | | | | | | | | | The refactor scan flagged three install/lint problems. I fixed all three. - The Makefile SKILLS list was hand-maintained and had drifted: `respond-to-cj-comments` exists on disk but wasn't installed by `make install`. I replaced the list with `$(patsubst %/SKILL.md,%,$(wildcard */SKILL.md))` so every directory containing a SKILL.md is picked up automatically. - Cross-references in installed skills point at `../claude-rules/foo.md`. The install layout puts rules at `~/.claude/rules/`, not `~/.claude/skills/claude-rules/`, so those links resolved in the source repo and silently broke at install. I added a bridge symlink to the install target. `~/.claude/skills/claude-rules` now points at the source `claude-rules/` directory, so the same relative path works in both layouts. - I extended `scripts/lint.sh` with a `check_md_links` function that validates `claude-rules/` cross-references in `claude-rules/*.md` and `*/SKILL.md`. Scoped narrowly on purpose: skill bodies cite illustrative file names (ADR templates, arc42 sections) that aren't real source files and would generate noise. Verified locally: `make install` is idempotent, the bridge resolves the previously-broken link, and `bash scripts/lint.sh` is clean.
* chore: remove fix-issue skill, superseded by start-workCraig Jennings2026-04-221-1/+1
| | | | | | | | | | | | The fix-issue skill has been replaced by start-work, which covers the same ground (picking up a ticket with a known fix and carrying it through to handoff) with a seven-phase structure and three user-approval gates. Deleted fix-issue/SKILL.md and swept the references. Updated: - Makefile SKILLS list: remove fix-issue, add start-work so make install creates the right symlink. - brainstorm/SKILL.md: implementation-path list points at start-work. - debug/SKILL.md description: both "do NOT use for ticket-driven work" and "Companion to" references updated. - review-code/SKILL.md description: "drafting implementation" redirect updated. No change in meaning. Every old fix-issue context now names start-work.
* skills: add create-v2mom; extend add-tests with refactor-for-testabilityCraig Jennings2026-04-191-1/+1
| | | | | | | | | | | | | | | | New standalone create-v2mom skill (converted from the homelab workflow template, markdown + YAML frontmatter, context-hygiene references removed in favor of the global session-context protocol). add-tests/SKILL.md gains a 'Core Principle — Refactor for Testability First' section and three inserts into the phase instructions: - Phase 1 flags testability-blocked functions during inventory - Phase 2 surfaces refactor-first candidates per function - Phase 3 adds a test-failure-vs-production-bug triage step Sourced from the retired refactor.org homelab workflow (which was a TDD-for-testability guide, not a general refactoring guide — general refactoring is already covered by the /refactor slash command).
* feat(hooks): add global hooks — PreCompact priorities + git/gh confirm modalsCraig Jennings2026-04-191-1/+47
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Three new machine-wide hooks installed via `make install-hooks`: - `precompact-priorities.sh` (PreCompact) — injects a priority block into the compaction prompt so the generated summary retains information most expensive to reconstruct: unanswered questions, root causes with file:line, subagent findings as primary evidence, exact numbers/IDs, A-vs-B decisions, open TODOs, classified-data handling. - `git-commit-confirm.py` (PreToolUse/Bash) — gates `git commit` behind a confirmation modal showing parsed message, staged files, diff stats, author. Parses both HEREDOC and `-m`/`--message` forms. - `gh-pr-create-confirm.py` (PreToolUse/Bash) — gates `gh pr create` behind a modal showing title, base ← head, reviewers, labels, assignees, milestone, draft flag, body (HEREDOC or quoted). Makefile: adds `install-hooks` / `uninstall-hooks` targets and extends `list` with a Hooks section. Install prints the settings.json snippet (in `hooks/settings-snippet.json`) to merge into `~/.claude/settings.json`. Also: `languages/elisp/claude/hooks/validate-el.sh` now emits JSON with `hookSpecificOutput.additionalContext` on failure (via new `fail_json()` helper) so Claude sees a structured error in context, in addition to the existing stderr output and exit 2. Patterns synthesized clean-room from fcakyon/claude-codex-settings (Apache-2.0). Each hook is original content.
* feat: add finish-branch skill (clean-room synthesis from obra/superpowers ↵Craig Jennings2026-04-191-1/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | pattern) Clean-room synthesis of the 'finishing a development branch' pattern from obra/superpowers (MIT) — adopted as the forced-choice workflow scaffold, not the substantive rules. Substantive rules defer to existing ones: - Verification → verification.md - Commit conventions + no AI attribution → commits.md - Review discipline → review-code Core patterns implemented: - Phase 1 verify-before-options (hard-stop on failing tests) - Phase 2 base branch + commit range + worktree detection - Phase 3 forced-choice menu (exactly 4 options, no editorializing, stop+wait) - Phase 4 execution per-option with: - Option 1 (merge locally): re-verify after merge, delete branch, prompt about remote-branch cleanup separately - Option 2 (push + PR): gh pr create with inline template (no AI attribution in the body); do NOT remove worktree - Option 3 (keep): no git state changes; preserve worktree - Option 4 (discard): typed-word "discard" confirmation gate required; lists what will be permanently lost; force-delete + remote cleanup - Phase 5 worktree cleanup matrix (cleanup for 1 and 4; preserve for 2 and 3) Notable over the upstream superpowers skill: - Explicit delegation to verification.md / commits.md / review-code rather than re-teaching those standards inline - Cross-references to /review-code (pre) and /arch-evaluate (if architectural) - Handles remote-branch cleanup question separately from local branch (upstream conflates them) - "Common Mistakes" section names the specific failure modes this skill prevents (open-ended "what now", accidental deletes, merge-then-oops, worktree amnesia, trailing AI attribution in PRs) Rubric coverage vs upstream: M (verify → options → execute → cleanup); M (forced-choice menu pattern); M (typed-discard confirmation gate); M (worktree cleanup matrix); M (hard-stop on failing tests); + (explicit deferral to existing rules vs upstream's inline rules); + (remote-branch cleanup as separate prompt); + (skill integration notes for /review-code and /arch-evaluate); no dropped capabilities. Makefile SKILLS extended; make install symlinks globally at ~/.claude/skills/finish-branch.
* refactor: review-pr → review-code with superpowers + plugin-lifted ↵Craig Jennings2026-04-191-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | improvements Renamed review-pr → review-code (the skill accepts PR, SHA range, current branch, staged changes — "pr" was understating scope). Rewrote SKILL.md with YAML frontmatter (previously header-style) and merged useful patterns from two sources: From obra/superpowers skills/requesting-code-review: - Intent-vs-delivery grading (given plan/ADR/ticket) - Mandatory Strengths section (three minimum) - Per-issue Critical/Important/Minor severity (per-criterion PASS/WARN/FAIL retained; complementary axes) - Required verdict + 1-2 sentence reasoning - Multi-input support (PR / SHA range / current branch / --staged) - Sub-agent dispatch recommendation for heavy reviews - Concrete filled-in example output From the claude-plugins-official code-review plugin: - Phase 0 eligibility gate (skip closed/draft/auto/trivial/already-reviewed) - CLAUDE.md traversal + adherence criterion (reads root + per-directory CLAUDE.md files; audits the diff against stated rules) - Multi-perspective Phase 2: five passes (CLAUDE.md adherence, shallow bug scan, git history context, prior PR comments, in-scope code comments). For large reviews, dispatch as parallel sub-agents. - Confidence filter (High/Medium/Low; drop Low before reporting) - False-positive categories explicitly enumerated (pre-existing issues on unmodified lines, lint/typecheck issues CI handles, senior-wouldn't-call-out nitpicks, silenced issues with valid reason, intentional scope changes, unmodified-line issues, framework-behavior tests) - Trust-CI discipline (don't run builds yourself) Substance from the original review-pr kept verbatim: - DeepSat-specific criteria (security, TDD evidence, conventions, no-AI-attribution, API contracts, architecture layering, root-cause discipline) Size: 60 lines → 347 lines. Growth is structural (added phases, added example, added perspectives, added filters) not verbose — each section earns its lines. NOT adopted from the plugin: - GitHub comment output format (plugin posts PR comments; review-code outputs a markdown report the user can paste if they want) - "Generated with Claude Code" footer (violates no-AI-attribution rule) - Specific 0/25/50/75/100 confidence scale (Critical/Important/Minor covers the same signal with less ceremony) Makefile SKILLS updated: review-pr → review-code. Old ~/.claude/skills/review-pr symlink removed; make install creates the new one at ~/.claude/skills/review-code.
* feat: adopt pairwise-tests (PICT combinatorial) + cross-reference from ↵Craig Jennings2026-04-191-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | existing testing skills Forked verbatim from omkamal/pypict-claude-skill (MIT). LICENSE preserved. Renamed from `pict-test-designer` to `pairwise-tests` — technique-first naming so users invoking "pairwise" or "combinatorial" find it; PICT remains the tool under the hood. Bundle (skill-runtime only): pairwise-tests/SKILL.md (renamed, description rewritten) pairwise-tests/LICENSE (MIT, preserved) pairwise-tests/references/pict_syntax.md pairwise-tests/references/examples.md pairwise-tests/scripts/pict_helper.py (Python CLI for model gen / output fmt) pairwise-tests/scripts/README.md Upstream's repo-level docs (README, QUICKSTART, CONTRIBUTING, etc.) and `examples/` dir (ATM + gearbox walkthroughs — useful as reading, not as skill-runtime) omitted from the fork. Attribution footer added. Cross-references so /add-tests naturally routes to /pairwise-tests when warranted: - add-tests/SKILL.md Phase 2 step 8: if a function in scope has 3+ parameters each taking multiple values, surface `/pairwise-tests` to the user before proposing normal category coverage. Default continues with /add-tests; user picks pairwise explicitly. - claude-rules/testing.md: new "Combinatorial Coverage" section after the Normal/Boundary/Error categories. Explains when pairwise wins, when to skip (regulated / provably exhaustive contexts, ≤2 parameters, non- parametric testing), and points at /pairwise-tests. - languages/python/claude/rules/python-testing.md: new "Pairwise / Combinatorial for Parameter-Heavy Functions" subsection under the parametrize guidance. Explains the pytest workflow: /pairwise-tests generates the matrix, paste into pytest parametrize block, or use pypict helper directly. Mechanism note: cross-references are judgment-based — Claude reads the nudges in add-tests/testing/python-testing and acts on them when appropriate, not automatic dispatch. Craig can still invoke /pairwise-tests directly when he already knows he wants combinatorial coverage. Makefile SKILLS extended; make install symlinks /pairwise-tests globally.
* feat: adopt frontend-design (Apache 2.0 fork) + progressive-disclosure ↵Craig Jennings2026-04-191-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | extensions Forked verbatim from anthropics/skills/skills/frontend-design (Apache 2.0). LICENSE.txt preserved. Upstream SKILL.md prose (aesthetic guidance, archetype list, anti-pattern callouts) kept intact. Extensions added (clearly marked, load progressively — base SKILL.md stays lean for simple cases): SKILL.md: - Description extended with explicit negative triggers: narrow maintenance (single CSS bug, dependency upgrade, a11y-only retrofit), operational contexts where stakeholder has specified "minimal, functional, no creative direction," backend / API work, non-web UIs (mobile native, desktop, terminal), and refactoring without visible design component. - New "Workflow" section at the end of SKILL.md: four phases (intake, commitment, build, review) with pointers to reference files. Simple component tweaks skip the workflow; non-trivial redesigns walk it. - New "References" section: table mapping file → load-when condition. - Attribution footer marking upstream source + what's locally added. references/workflow.md (~150 lines) Intake questions (purpose, audience, operational context, functional priority, technical constraints, brand references, success criteria). Commitment step (archetype pick, trade-offs, font pairing, palette, motion, layout as one-line decisions). Build reminders. Review pointer. Guidance on when to skip phases. references/accessibility.md (~200 lines) WCAG AA contrast thresholds + practical check guidance. Keyboard navigation + focus management. Semantic HTML + ARIA rules. Reduced- motion CSS snippet. Smoke checklist. Operational-context note for defense / ISR work. references/responsive.md (~160 lines) Mobile-first vs desktop-first decision. Named breakpoints (Tailwind- style) vs magic pixels. Container queries. Aesthetic translation table — how each archetype handles small-screen scaling. Responsive typography with clamp(). Operational-dashboard note: desktop-primary is a legitimate product decision. references/design-review.md (~170 lines) Archetype check (does the build read as what was committed to?). Anti-pattern grep for fonts, palette, layout, motion, backgrounds, components. Code-quality-match check (ornate design + lazy code = failure). Performance sanity. Convergence check (if last 3 builds all used the same archetype, break the pattern). The one-sentence test for memorability. references/rationale-template.md (~160 lines) Template for design-rationale.md alongside the build. Nine sections (purpose, archetype, locked decisions, deliberately absent, accessibility, responsive, implementation, open questions, references). Filled example using a DeepSat SOCOM demo landing page to show density and specificity. Structure matches Anthropic's own pdf / docx / webapp-testing pattern (SKILL.md entry + references/ for progressive disclosure). Makefile SKILLS extended; make install symlinks globally. Adoption caveat resolved: name kept as `frontend-design` (not renamed to ui-design) — "frontend" signals scope (web code, not mobile / desktop / terminal UIs), upstream parity preserved for attribution.
* fix(deps): use uv tool install for playwright-py; gitignore node_modulesCraig Jennings2026-04-191-6/+12
| | | | | | | | | | | | | | | | | | | | | Two fixes rolled up: 1. Add .gitignore with **/node_modules/, package-lock.json, Python venv / cache artifacts, and OS metadata. Prior make deps run produced a 603- file playwright-js/node_modules tree that should never be tracked. 2. Makefile deps target: install playwright-py via `uv tool install playwright` instead of `pip install --system`. Earlier attempts with pip --user, pip --system, and uv pip --system all failed on externally- managed Python (PEP 668 on Arch). `uv tool install` creates an isolated venv for the CLI, avoiding the conflict. Chromium browsers are shared with the JS side via ~/.cache/ms-playwright — no re-download. Also added uv itself to the deps target (was missing). Library import (`import playwright`) still requires per-project venv, which is the right pattern on externally-managed systems. Deps output mentions this explicitly.
* refactor(playwright): split into playwright-js + playwright-py variantsCraig Jennings2026-04-191-7/+18
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Rename `playwright-skill/` → `playwright-js/` and add `playwright-py/` as a verbatim fork of Anthropic's official `webapp-testing` skill (Apache-2.0). Cross-pollinate: each skill gains patterns and helpers inspired by the other's strengths, with upstream semantics preserved. ## playwright-js (JS/TS stack) Renamed from playwright-skill; upstream lackeyjb MIT content untouched. New sections added (clearly marked, preserving upstream semantics): - Static HTML vs Dynamic Webapp decision tree (core Anthropic methodology) - Reconnaissance-Then-Action pattern (navigate → networkidle → inspect → act) - Console Log Capture snippet (page.on console/pageerror/requestfailed) Description updated to clarify JS/TS stack fit (React/Next/Vue/Svelte/Node) and reference `/playwright-py` as the Python sibling. ## playwright-py (Python stack) Verbatim fork of anthropics/skills/skills/webapp-testing; upstream SKILL.md and bundled `scripts/with_server.py` + examples kept intact. New scripts and examples added (all lackeyjb-style conveniences in Python): Scripts: scripts/detect_dev_servers.py Probe common localhost ports for HTTP servers; outputs JSON of found services. scripts/safe_actions.py safe_click, safe_type (retry-wrapped), handle_cookie_banner (common selectors), build_context_with_headers (env-var- driven: PW_HEADER_NAME / PW_HEADER_VALUE / PW_EXTRA_HEADERS='{…json…}'). Examples: examples/login_flow.py Login form + wait_for_url. examples/broken_links.py Scan visible external hrefs via HEAD. examples/responsive_sweep.py Multi-viewport screenshots to /tmp. SKILL.md gains 5 "Added:" sections documenting the new scripts, retry helpers, env-header injection, and /tmp script discipline. Attribution notes explicitly mark upstream vs local additions. ## Makefile SKILLS: playwright-skill → playwright-js + playwright-py deps target: extended Playwright step to install Python package + Chromium via `python3 -m pip install --user playwright && python3 -m playwright install chromium` when playwright-py/ is present. Idempotent (detected via `python3 -c "import playwright"`). ## Usage Both skills symlinked globally via `make install`. Invoke whichever matches the project stack — cross-references in descriptions route you to the right one. Run `make deps` once to install both runtimes.
* feat: adopt lackeyjb/playwright-skill (MIT verbatim fork) + deps targetCraig Jennings2026-04-191-12/+27
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Browser automation + UI testing skill forked verbatim from github.com/lackeyjb/playwright-skill (MIT, 2458 stars, active through Dec 2025). LICENSE preserved in skill dir with attribution footer added to SKILL.md. Bundle contents (from upstream): playwright-skill/SKILL.md playwright-skill/API_REFERENCE.md playwright-skill/run.js (universal executor with module resolution) playwright-skill/package.json playwright-skill/lib/helpers.js (detectDevServers, safeClick, safeType, takeScreenshot, handleCookieBanner, extractTableData, createContext with env-driven header injection) playwright-skill/LICENSE (MIT, lackeyjb) Makefile updates: - SKILLS extended with playwright-skill; make install symlinks it globally into ~/.claude/skills/ - deps target extended to check node + npm, and to run the skill's own `npm run setup` (installs Playwright + Chromium ~300 MB on first run). Idempotent: skipped if node_modules/playwright already exists. Stack fit: JavaScript Playwright aligns with Craig's TypeScript/React frontend work. Python-side (Django) browser tests would be better served by Anthropic's official webapp-testing skill (Python Playwright bindings), noted in the evaluation memory but not adopted here — minimal overlap, easy to add later if the need arises.
* feat: clean-room synthesis — prompt-engineering skillCraig Jennings2026-04-191-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | Distilled from NeoLab customaize-agent:prompt-engineering rubric (GPL-3.0 source; clean-room, no prose reused). ~17 KB NeoLab version trimmed to tighter ~430 lines focused on what's genuinely non-obvious: - Four prompt-type classification (discipline-enforcing / guidance / collaborative / reference), with explanations for each so the user knows what they're picking. Used in both design and critique modes. - Seven persuasion principles (Meincke et al. 2025, N≈28,000), with by-type matrix. Notably flags Liking as actively harmful for collaborative prompts (breeds sycophancy in reviews/critiques). - Degrees-of-freedom axis (high/medium/low) matched to task fragility. - Context-window-as-shared-resource framing. - Brief reference only for classical techniques (few-shot, CoT, system prompts, templates) — widely documented elsewhere, not re-taught. - Explicit ethics test for persuasion use. - Design-mode vs critique-mode workflows. - Anti-patterns list covering sycophancy-by-default, hedging-on- discipline-prompts, authority-stack-on-guidance, high-freedom-on- fragile-tasks. Landscape: no prompt-engineering skill exists in Anthropic's official repo, wshobson/agents, or the major community skill collections. Real gap. Makefile SKILLS extended; global symlink installed.
* rename: memorize → codifyCraig Jennings2026-04-191-1/+1
| | | | | | | | | | | | | "memorize" implied passive storage (same mental model as auto-memory). "codify" captures the actual operation: editorial selection, specific phrasing, deliberate commit to a lasting artifact. Changes: - memorize/ → codify/ - SKILL.md: name: codify; title updated; all references changed - Default CLAUDE.md section: ## Memorized Insights → ## Codified Insights - Makefile SKILLS updated - Old ~/.claude/skills/memorize symlink removed; codify symlink created
* feat: clean-room synthesis — brainstorm, memorize, root-cause-trace, five-whysCraig Jennings2026-04-191-1/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Four new skills synthesized from patterns in NeoLabHQ/context-engineering-kit (GPL-3.0). Clean-room approach: extracted rubrics from the originals (triggers, phases, hard cases, footguns, novel patterns), then wrote from scratch without referencing their prose. Ideas and methods aren't copyrightable; wording is. These skills are independent works. brainstorm Turn a vague idea into a validated design doc. Three phases: one-question-at-a-time dialogue, six-approach exploration (three conventional + three diverse tail samples for anti-convergence), chunked design presentation with per-chunk validation. Output: docs/design/<topic>.md. Hands off to arch-decide / arch-design / implementation. memorize Curate session insights into project CLAUDE.md under a dedicated "## Memorized Insights" section. Grow-and- refine per ACE (arXiv:2510.04618): atomic, evidence- backed, non-redundant bullets. Args: --dry-run, --max, --target, --section, --source. Flags cross-project patterns for promotion to ~/code/rulesets/claude-rules/. Clearly delineates from auto-memory (private) and formal rules (stable policy). root-cause-trace Backward-walk technique for debugging. Observe symptom → identify immediate cause → walk up the call chain → find original trigger → fix at source + defense-in- depth at each intermediate layer. Instrumentation guidance (stack capture before the dangerous op, not after; stderr not framework logger in tests); test- pollution bisection. Companion to /debug — /debug is broader; this is specifically the backward walk. five-whys Iterative why-questioning from symptom to process/ decision root cause. Five is a convention, not a quota — stop when a cause, if eliminated, would prevent every symptom in the chain. Handles branching (multiple contributing causes). Validates chains by walking back from root to symptom. Refuses to terminate at "human error" or "not enough budget" — those have deeper whys. Companion to root-cause-trace (that's for code execution; this is for process). Makefile SKILLS extended. make install symlinks all four into ~/.claude/skills/ alongside existing skills. Lint clean.
* feat: architecture skill suite — design, decide, document, evaluateCraig Jennings2026-04-191-1/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Four chained Claude Code skills covering the full architecture lifecycle: arch-design Intake (stakeholders, scale, quality attributes, constraints) → candidate paradigms with honest trade-off analysis → recommendation + open-decision list → .architecture/brief.md arch-decide ADR creation and management. Five template variants (MADR, Nygard, Y-statement, lightweight, RFC). Lifecycle, review process, adr-tools automation. Forked from wshobson/agents (MIT). LICENSE preserved. arch-document Full arc42-structured documentation (12 sections) from brief + ADRs + codebase. Dispatches to c4-analyze / c4-diagram for Context, Building Block, Runtime, Deployment diagrams. arch-evaluate Audits implementation against stated architecture. Framework-agnostic checks (cyclic deps, stated-layer violations, public API drift, forbidden deps) run on any language. Opportunistically invokes language-specific linters when configured (dependency-cruiser for TS, import-linter for Python, go vet + depguard for Go). Never installs tooling. Supporting docs at docs/architecture/: - README.md suite overview, install steps, per-language linter install commands (Python import-linter, TS dependency-cruiser, Go golangci-lint, Java ArchUnit future, C/C++ IWYU future), typical flow through the chain - v2-todo.org deferred features (auto-gen linter configs, ArchUnit, CI mode, DDD aggregate boundaries, visual dep graphs, retroactive layering inference) Makefile SKILLS extended with the four new entries; make install symlinks them to ~/.claude/skills/ alongside existing skills. Landscape: arch-decide fills the well-covered ADR bucket by adopting the strongest community offering rather than reinventing. arch-design and arch-evaluate fill gaps where no general-purpose skill existed. arch-document fills the arc42 gap (C4 diagrams already covered by sibling skills).
* feat(makefile): add deps, diff, lint targets and fzf-picker fallbackCraig Jennings2026-04-191-33/+79
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Ports useful quality-of-life targets from DeepSat's coding-rulesets Makefile, adapted to this repo's two-scope (global + per-project) structure. New targets: make deps Install claude, jq, fzf, ripgrep, emacs via brew/apt/pacman. Idempotent (skips already-present tools). For new machines and VMs. make diff LANG=<lang> [PROJECT=<path>] Show unified diff between repo source and installed copies in a target project. CLAUDE.md excluded (seed- only, diverges by design). make lint Validate ruleset structure: top-level headings, 'Applies to:' headers on rule files, shebangs and exec bits on hook scripts. Infrastructure: - Help migrated to awk-parsed ##@/## pattern; new targets document themselves via a single trailing `## ...` comment. - fzf-picker fallback: if PROJECT= is unset, install-lang and diff launch fzf over local .git dirs under $HOME. Keeps PROJECT=<path> for scripts/automation; only interactive users hit fzf. scripts/diff-lang.sh Walks the file list the installer would copy, diffs each against the target. scripts/lint.sh Standalone ruleset structure validator.
* refactor: generalize testing.md, split Python specifics, DRY installCraig Jennings2026-04-191-1/+5
| | | | | | | | | | | | | | | | | | | claude-rules/testing.md is now language-agnostic (TDD principles, test categories, coverage targets, anti-patterns). Scope header widened to **/*. Python-specific content (pytest, fixtures, parametrize, anyio, Django DB testing) moved to languages/python/claude/rules/python-testing.md. Added languages/python/ bundle (rules only so far; no CLAUDE.md template or hooks yet — Python validation tooling differs from Elisp). Added install-python shortcut to the Makefile. Updated scripts/install-lang.sh to copy claude-rules/*.md into each target project's .claude/rules/. Bundles no longer need to carry their own verification.md copy — deleted languages/elisp/claude/rules/verification.md. Single source of truth in claude-rules/, fans out via install. Elisp-testing.md now references testing.md as its base (matches the python-testing.md pattern).
* feat: add per-project language bundles + elisp rulesetCraig Jennings2026-04-191-1/+34
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | Introduces a second install mode alongside the existing global symlinks: per-project language bundles that copy a language-specific Claude Code setup (rules, hooks, settings, pre-commit) into a target project. Layout additions: languages/elisp/ - Emacs Lisp bundle (rules, hooks, settings, CLAUDE.md) scripts/install-lang.sh - shared install logic Makefile additions: make help - unified help text make install-lang LANG=<lang> PROJECT=<path> [FORCE=1] make install-elisp PROJECT=<path> [FORCE=1] (shortcut) make list-languages - show available bundles Elisp bundle contents: - CLAUDE.md template (seed on first install, preserved on update) - .claude/rules/elisp.md, elisp-testing.md, verification.md - .claude/hooks/validate-el.sh (check-parens, byte-compile, run matching tests) - .claude/settings.json (permission allowlist, hook wiring) - githooks/pre-commit (secret scan + staged-file paren check) - gitignore-add.txt (append .claude/settings.local.json) Hooks use \$CLAUDE_PROJECT_DIR with a script-relative fallback, so the same bundle works on any machine or clone path. Install activates git hooks via core.hooksPath=githooks automatically. Re-running install is idempotent; CLAUDE.md is never overwritten without FORCE=1.
* chore: remove non-functional hooks templateCraig Jennings2026-04-141-15/+1
| | | | | | | | | | | | The hooks/settings.json template was broken since day one: - PostEditTool is not a valid Claude hook event - PreCommit is not a Claude concept at all - matcher was used as a glob, not a tool-name regex - $FILE was never substituted from stdin JSON Hooks never fired. Formatting and secret-scanning belong in CI and pre-commit frameworks, not per-developer Claude config. Remove the template and its install-hooks Makefile target.
* Add hooks settings.json with install-hooks targetCraig Jennings2026-03-291-1/+15
| | | | | | | | | | | Hooks provide: - PostEditTool: ruff format/check on Python, terraform fmt on .tf - PreCommit: block commits containing hardcoded secrets (AWS keys, API tokens, passwords) Install per-project with: make install-hooks TARGET=/path/to/project Won't overwrite existing settings.json — shows diff command instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Add general-purpose skills and rules from DeepSat coding-rulesetsCraig Jennings2026-03-291-2/+42
| | | | | | | | | | | | | | | | | | Skills (adapted from DeepSat, stripped of project-specific references): - /review-pr: PR review against engineering standards - /fix-issue: issue-to-merge TDD workflow - /security-check: secrets, OWASP, and dependency audit - /debug: systematic 4-phase debugging - /add-tests: test coverage analysis and generation - /respond-to-review: evaluate and implement code review feedback Rules (general-purpose, copied as-is): - testing.md: universal TDD standards and anti-patterns - verification.md: proof over assumption Makefile updated to install both skills and rules via symlinks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>