CLAUDE.md — hdatools
Source:CLAUDE.md
hdatools is an R package of branded ggplot2 themes, color scales, and helper functions for HDAdvisors / HousingForward Virginia projects. Proprietary (License: file LICENSE).
Running R (read this first)
Run R via the Rscript on the caller’s PATH — assume it resolves to a working R install. Don’t hard-code an install path or version anywhere; those differ across machines and change on every R upgrade. If Rscript isn’t on PATH, don’t guess where R lives — stop and tell the user, and point them to add R’s bin directory to PATH (or to supply the path to their Rscript).
Claude Code on the web / cloud sessions provision R automatically. A SessionStart hook (.claude/hooks/session-start.sh + install-r-deps.R, registered in .claude/settings.json) installs r-base, pandoc, the compiled-package system libs, and the full R dev toolchain (devtools, roxygen2, testthat, pkgdown, urlchecker, spelling, plus DESCRIPTION’s own Imports/Suggests) the first time a cloud session touches this repo. It needs cloud.r-project.org allowlisted in the environment’s network policy (Custom network access → Allowed domains) — without it, the hook installs R itself fine but every package install fails. If Rscript still isn’t on PATH in a cloud session, check the hook’s output before concluding R is unavailable; the “stop and tell the user” rule above is for local sessions. Installs build from source (no binary mirror is reachable through the network policy), so the first cold container takes a while — expect the result to be cached in later sessions. None of this applies locally — Jonathan’s machine manages its own R install per the rules above.
Never run R inline (Rscript -e "...") — Windows shell quoting mangles it. Always write the R code to a temp file and execute that file:
Start each script with setwd() pointing at this repo’s root (the folder that contains DESCRIPTION) so devtools/pkgdown find the package.
DESCRIPTION’s Imports/Suggests plus devtools, roxygen2 (matching Config/roxygen2/version), and pkgdown must all be installed.
The dev loop
Run these in order after changing R source or roxygen comments:
-
devtools::document()— regeneratesNAMESPACEandman/*.Rdfrom roxygen. -
devtools::test()— full testthat suite (edition 3). -
devtools::check()—R CMD check. Target: 0 errors, 0 warnings. The only accepted NOTE is the proprietary-license one (Non-standard license specification: file LICENSE). Any other NOTE is a regression — investigate it. In a cloud session, expect two additional NOTEs that aren’t regressions: installed package size (the bundled fonts are 4.8Mb) and “unable to verify current time” (the future-timestamp check needs a network host this environment’s policy blocks). Anything beyond those three is worth investigating same as locally. -
pkgdown::build_site()— rebuilds the site intodocs/. Two gotchas when running via standalone Rscript (no RStudio):- pkgdown/rmarkdown need Pandoc, which a bare
Rscriptmay not find. If a build fails with “Pandoc not available,” point R at a bundled copy viaSys.setenv(RSTUDIO_PANDOC = <dir>)— Quarto and RStudio each ship one in atoolsdirectory. Locate the copy on the current machine rather than assuming a path. (Cloud sessions get a systempandocfrom the SessionStart hook, already onPATH— this workaround is for local sessions without RStudio/Quarto installed.) -
build_site()re-knits every article invignettes/articles/. As of 0.5.0branded-themes.Rmduses a small bundled data table instead of a livetidycensus::get_acs()call, so it no longer needs a Census API key or network to build. For faster doc/theme iteration you can still rebuild only what changed:init_site()+build_home()+build_reference()+build_news()+build_articles().
- pkgdown/rmarkdown need Pandoc, which a bare
Generated files — never hand-edit
-
NAMESPACEand everything underman/are generated by roxygen2. Edit the roxygen comments above the function and re-rundevtools::document(). - Everything under
docs/is generated by pkgdown. Never hand-edit it; change the source (roxygen,README.md,_pkgdown.yml, articles) and rebuild. -
Roxygen markdown mode is on (
Roxygen: list(markdown = TRUE)in DESCRIPTION). Write Markdown in roxygen comments (**bold**,`code`,[text](url)); it is converted to Rd markup ondocument(). Don’t hand-write\strong{}/\code{}.
Testing conventions
- testthat 3e. Structural theme/scale assertions run through
ggplot2::ggplot_build()/calc_element()so no fonts are needed to test. - Mock output-format detection with
local_mocked_bindings(is_html_output = function(...) TRUE, .package = "knitr"); mock the ggiraph Suggests guard withlocal_mocked_bindings(requireNamespace = function(...) FALSE, .package = "base"). - Never modify a test just to make it pass. A red test is a finding about the code, not the test. Fix the code, or — if the behavior change is intentional — change the test deliberately and say so.
-
Snapshots update only for intentional changes. Review every snapshot diff (
testthat::snapshot_review()) before accepting; never blanket-accept.
Release checklist
- Decide the version. Dev work sits at
x.y.z.9000; a release drops the.9000(e.g.0.2.1or0.3.0). - Update
DESCRIPTIONVersion:and move the NEWS.md# hdatools (development version)heading to the release version. - Verify NEWS.md claim-by-claim against the code — no aspirational entries.
-
devtools::document()→devtools::test()→devtools::check()(0 errors / 0 warnings; license NOTE only). -
urlchecker::url_check()— catch dead/redirected URLs in DESCRIPTION, README, and man pages. -
spelling::spell_check_package()— review flagged words; add genuine terms toinst/WORDLIST. -
pkgdown::build_site()and commit the regenerateddocs/. - Commit; tag annotated
vX.Y.Z;git push --tags. - Commit messages: no Claude/Anthropic co-author line.
Consumer rollout (pinned repos: pha-update-2026, fhfh, faar) happens in those repos’ own sessions — bump the pin, renv::snapshot(), re-render, compare. Never force a consumer bump as a drive-by. See plans/consumer-rollout.md for the reusable procedure.
Skills
.claude/skills/ vendors three MIT-licensed skills from posit-dev/skills — see .claude/skills/VENDORED.md:
-
create-release-checklist— generate a release checklist + GitHub issue. -
r-package-development— the devtools/roxygen2/testthat loop. -
testing-r-packages— testthat 3e conventions, fixtures, mocking, snapshots.
They assume R is on PATH with inline Rscript -e; use the temp-file convention above instead.
Contributing and dev process
See CONTRIBUTING.md for the getting-started guide, versioning convention, release-when-ready flow, NEWS/test/docs rules, and how to file issues. The release checklist below is the authoritative step list; CONTRIBUTING.md references it.
Planning docs
plans/ is build-ignored (^plans$ in .Rbuildignore) and contains two kinds of content:
-
Durable reference docs —
DECISIONS.md(append-only log of settled design decisions) andconsumer-rollout.md(reusable release rollout procedure). Both are actively referenced from CONTRIBUTING.md and this file; don’t archive them. -
Working notes — everything else. Executed phase plans move to
plans/archive/with a short completion header; their content is left intact for history.