aspi6246/code-sweep
> End-of-milestone audit of a research project's `Code/` folder against the paper and outputs. Surfaces drift between scripts, YAML headers, the script registry, outputs, raw data, and the paper. Categorises findings as MUST-FIX or SUGGESTED and proposes fixes one at a time for the user to confirm. Use this skill when the user says "code sweep", "sweep the code", "run a code sweep", "audit my code folder", "check code freshness", "is everything up to date", "any stale outputs", "audit code consistency", or similar — typically before a paper submission, milestone, or share. Extends `script-registry`; builder rather than redefining either.
npx skills add https://github.com/aspi6246/Claude-Code-Skills-for-Academics --skill code-sweep
Audit a research project for drift between scripts, outputs, raw data, and the paper. Propose fixes one at a time; the user confirms each. This skill extends script-registry — it reuses that skill's YAML schema, builder, and folder conventions. The only YAML additions Code Sweep introduces are status: and seed:.
/code-sweep — full sweep (all checks)/code-sweep --quick — structural checks only; skips dry-run + paper cross-ref/code-sweep --sample N — override dry-run sample size (default 1000)/code-sweep --no-dryrun — skip just the dry-run step/code-sweep --no-paper — skip just the paper cross-ref stepIf invoked via trigger phrase, default to full sweep unless the user qualifies ("quick code sweep", etc.).
Read the project's CLAUDE.md (in the current working directory) for folder paths. Default conventions (inherited from script-registry):
| Purpose | Default path |
|---|---|
| Scripts | Code/ |
| Working/purled scripts | Code/_Claude Scripts/ |
| Archived scripts | Code/_Archive/ and Code/_Claude Scripts/_Archive/ |
| Figures | Output/Figures/ |
| Tables | Output/Tables/ |
| Processed data | Output/Processed Data/ |
| Raw data | Data/ |
| Paper | Paper/ |
| Main paper file | Paper/main.tex |
| Session logs | Code/_Claude Session Logs/ |
| Registry view | Code/REGISTRY.md |
| Registry builder | Code/_Claude Scripts/build_registry.R |
If the project's CLAUDE.md declares different paths, use those. If no Code/ folder exists, abort with: "This doesn't look like a research project (no Code/ folder). Code Sweep is designed for empirical-finance research projects."
script-registry already defines the registry: block (purpose, inputs, outputs, paper_target, notes). Code Sweep adds two optional fields:
registry:
purpose: "..."
inputs:
- Data/Processed/foo.parquet
outputs:
- Output/Figures/fig_descriptive_stats.pdf
- Output/Tables/tab_main_results.tex
paper_target: "Table 1, Figure 3"
notes: "..."
status: active # NEW — active | deprecated. Default: active if absent.
seed: 42 # NEW — required iff script uses randomness.
produces_figures / produces_tables are not added — they're derivable from outputs: by extension (.pdf/.png → figure, .tex → table).
Inherit script-registry's convention:
^\d+[a-z]?\. Claude_[A-Za-z0-9_]+\.Rmd$ (e.g. 3. Claude_Clean_Data.Rmd, 12b. Claude_Run_Models.Rmd)^fig_[a-z0-9_]+\.(pdf|png|jpg)$ in Output/Figures/^tab_[a-z0-9_]+\.tex$ in Output/Tables/If the project's existing files don't follow these patterns, prefer the project's actual convention — sample a few existing files to infer the pattern and check the rest against that, rather than rigidly enforcing the default.
Run in this order. Tag each finding MUST-FIX or SUGGESTED. Skip checks gated by --quick / --no-dryrun / --no-paper.
M1. registry: block completeness — for every .Rmd in Code/ (non-recursive, excluding _Archive/):
registry: block existspurpose, inputs, outputs are present (inputs/outputs may be empty lists)inputs: paths actually exist on diskoutputs: paths actually exist on disk (the script may not have been run yet — if status is active and outputs are missing, flag MUST-FIX; if status: deprecated, demote to SUGGESTED)M2. Paper cross-reference *(skip on --quick or --no-paper)* — parse the paper:
Paper/main.tex (or whatever CLAUDE.md designates).\input{...} and \include{...} to sub-files.\graphicspath{{path1/}{path2/}} if present.\includegraphics[...]{stem} and \input{...} reference (ignore commented lines).Output/Figures/ (try .pdf, .png, .jpg) AND some active script's outputs: must list it.Output/Tables/ (.tex) AND some active script's outputs: must list it.Missing file OR missing producing script → MUST-FIX. Don't compile the paper — this is parse-based.
M3. Dry-run viability *(skip on --quick or --no-dryrun)* — for each status: active script:
Rscript -e "knitr::purl('Code/<script>.Rmd', output=tempfile(fileext='.R'), quiet=TRUE)" options(.codesweep_sample = <N from --sample>)
options(.codesweep_dryrun = TRUE)
Rscript --vanilla with a 120s timeout.Scripts that respect .codesweep_sample should sample their data loads. Scripts that don't will run on full data — slower but still informative. Document this convention in the project's CLAUDE.md if it's not already.
M4. Registry sync — run Rscript "Code/_Claude Scripts/build_registry.R" (or whatever the project uses). After it completes:
Code/REGISTRY.md.If build_registry.R doesn't exist, suggest invoking the script-registry skill to set it up, then abort this check.
M5. Reproducibility — set.seed() — grep each active .Rmd for randomness markers: sample(, rnorm(, runif(, rbinom(, rpois(, rbeta(, rgamma(, kmeans(, boot(, bootstrap(, Sys.setenv.*SEED. If any are present:
seed: must be declared in the registry: blockset.seed(<the registry seed>) somewhere before the randomnessMissing seed OR mismatched seed → MUST-FIX.
S1. Stale outputs — for each declared output, compare its mtime to each declared input's mtime. If any input is newer than this output → flag staleness. Report only ("fig_x.pdf is older than data/raw_y.parquet"). Don't propose re-running. The user knows whether the staleness matters.
S2. Orphan outputs — files in Output/Figures/, Output/Tables/, Output/Processed Data/ not declared in any active script's outputs: → SUGGESTED. Propose: move to Output/_Archive/ (create if missing) OR delete (only if user explicitly says delete).
S3. Orphan inputs — files under Data/ not referenced in any active script's inputs: → SUGGESTED. Don't propose deletion (raw data is precious); just flag.
S4. Naming-convention violations — files in Code/, Output/Figures/, Output/Tables/ that don't match the patterns in Step 3 → SUGGESTED with proposed rename. Do not auto-rename — every rename also requires updating outputs: declarations and possibly the paper's \includegraphics references. Propose the rename and the corresponding YAML/paper edits as one bundle.
S5. Deprecated or DAG-orphan scripts — flag a script as a candidate for Code/_Archive/ if:
status: deprecated, ORinputs: references any of its outputs, AND none of its outputs appear in the paper cross-ref set from M2→ SUGGESTED move to Code/_Archive/. Per project rule: move, never delete.
S6. Loose .R files in Code/ — any .R file directly under Code/ (not in _Claude Scripts/) that isn't the pipeline orchestrator (Code/00_run_pipeline.R or whatever CLAUDE.md designates) → SUGGESTED move to Code/_Claude Scripts/. Likely a purled or temp script that didn't get filed.
S7. TODO/FIXME inventory — grep \b(TODO|FIXME|XXX|HACK)\b across Code/ (excluding _Archive/). Report each match as file:line:text, grouped by file. Informational only — no proposed fix.
S8. Environment manifest sync — collect every library(pkg), require(pkg), and pkg::fn reference across Code/ (excluding _Archive/). Compare to renv.lock if present, or DESCRIPTION / requirements.txt. Packages referenced but not in the lockfile → SUGGESTED. If no lockfile exists, suggest creating one with renv::init().
Append the sweep results to today's session log at Code/_Claude Session Logs/YYYY-MM-DD.md (the same convention as wrap-up: one file per day, multiple sessions append with a horizontal-rule separator). If the project's CLAUDE.md designates a different log path or filename pattern, follow that instead. Create the log file if it does not exist.
If the day's log already contains content, append with a leading horizontal rule (---) and timestamped section header. The sweep does not replace any prior content.
Format:
---
## Code Sweep — <YYYY-MM-DD HH:MM>
**Invocation:** `/code-sweep <args>`
**Mode:** full | quick | partial (note skipped checks)
### Summary
- MUST-FIX: <N> findings
- SUGGESTED: <M> findings
### MUST-FIX
#### M1.a — `registry:` block missing `inputs:` in `3. Claude_Clean_Data.Rmd`
**Issue:** YAML block missing required field.
**Proposed fix:** add `inputs: [Data/raw/firms.parquet]` based on detected `read_parquet()` call at line 42.
**Status:** pending
(... one block per finding ...)
### SUGGESTED
(... same format ...)
### Outcome
- Applied: <N>
- Declined: <M> (reasons below)
- Deferred to PINBOARD.md: <K>
Update each finding's Status: line as the user responds: pending → applied | declined: <reason> | deferred.
Present findings one at a time, MUST-FIX first, in this order:
y — apply the fix, update Status to applied.n — ask for a one-line reason, record declined: <reason>.skip — leave Status pending, revisit at end of pass.defer — append to PINBOARD.md (use the pinboard skill if available), Status deferred.explain — give more context on why this is flagged, then re-ask.Batch shortcut: when 3+ consecutive findings share the same check ID (e.g., multiple S4 naming violations), after the first one offer: "Apply this same fix to all remaining S4 findings? [y/n]". If y, apply en bloc and report the count.
When all findings are processed:
N applied, M declined, K deferred).status: active default). The whole skill is propose-and-confirm._Archive/ only. This is a project ground rule._Archive/ contents. It's the dumping ground.script-registry's logic. Use its builder, read its REGISTRY.md, trust its drift detection. Code Sweep adds checks that span beyond the registry (paper cross-ref, dry-run, orphans, naming, TODOs, env manifest).pinboard skill). If the user wants pinboard entries, just write directly to PINBOARD.md using the existing format the project uses.\if...\else...\fi branches. Figures inside dead branches will look "missing" — user can decline those findings.registry: declarations are accurate. Stale or incomplete declarations produce false positives. Run M4 (registry sync) first so drift warnings surface before orphan checks.Run Code Sweep:
Code/Don't run Code Sweep mid-development on a single script — it's a milestone tool, not a per-commit linter.
Take aspi6246/code-sweep from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.