From 2e12753879ad10a5a30e3525c7db9a4593ab4e53 Mon Sep 17 00:00:00 2001 From: Steve Calvert Date: Mon, 12 Oct 2026 17:28:55 -0700 Subject: [PATCH 1/2] chore: add REVIEW.md and agent permission rules REVIEW.md holds this repo's review rules for people and review agents. .claude/settings.json holds the agent permission rules in Claude Code syntax (draft-pr preset), AGENTS.md carries the same rules in prose plus the commit and PR conventions, and .codex/rules/permissions.rules compiles them for Codex. Generated with configure-agents review. --- .claude/settings.json | 40 ++++++++++++++++++++++++ .codex/rules/permissions.rules | 18 +++++++++++ AGENTS.md | 56 ++++++++++++++++++++++++++++++++++ CLAUDE.md | 2 ++ REVIEW.md | 31 +++++++++++++++++++ 5 files changed, 147 insertions(+) create mode 100644 .claude/settings.json create mode 100644 .codex/rules/permissions.rules create mode 100644 AGENTS.md create mode 100644 REVIEW.md diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..8088f7b --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,40 @@ +{ + "permissions": { + "allow": [ + "Bash(git push *)", + "Bash(gh pr create --draft *)" + ], + "ask": [ + "Bash(gh pr comment *)", + "Bash(gh pr review *)", + "Bash(gh pr close *)", + "Bash(gh issue create *)", + "Bash(gh issue comment *)", + "Bash(gh issue close *)", + "Bash(gh release *)", + "Bash(npm publish *)", + "Bash(pnpm publish *)", + "Bash(yarn npm publish *)", + "Bash(git push -f *)", + "Bash(git push * -f)", + "Bash(git push * -f *)", + "Bash(git push *--force*)", + "Bash(git push * main)", + "Bash(git push * master)", + "Bash(git push *:main)", + "Bash(git push *:master)", + "mcp__*github*__create_*", + "mcp__*github*__add_*", + "mcp__*github*__update_*", + "mcp__*github*__merge_*", + "mcp__*github*__submit_*", + "mcp__*github*__delete_*", + "mcp__*github*__push_*", + "mcp__*slack*__*post*", + "mcp__*slack*__*send*", + "Bash(gh pr merge *)", + "Bash(gh pr ready *)" + ], + "deny": [] + } +} diff --git a/.codex/rules/permissions.rules b/.codex/rules/permissions.rules new file mode 100644 index 0000000..811cfff --- /dev/null +++ b/.codex/rules/permissions.rules @@ -0,0 +1,18 @@ +# Generated from .claude/settings.json. Do not edit; regenerate instead. +# Rules that Codex prefix rules cannot express need a PreToolUse hook. + +prefix_rule(pattern=["gh","pr","comment"], decision="prompt", justification="repo rule ask: Bash(gh pr comment *)") +prefix_rule(pattern=["gh","pr","review"], decision="prompt", justification="repo rule ask: Bash(gh pr review *)") +prefix_rule(pattern=["gh","pr","close"], decision="prompt", justification="repo rule ask: Bash(gh pr close *)") +prefix_rule(pattern=["gh","issue","create"], decision="prompt", justification="repo rule ask: Bash(gh issue create *)") +prefix_rule(pattern=["gh","issue","comment"], decision="prompt", justification="repo rule ask: Bash(gh issue comment *)") +prefix_rule(pattern=["gh","issue","close"], decision="prompt", justification="repo rule ask: Bash(gh issue close *)") +prefix_rule(pattern=["gh","release"], decision="prompt", justification="repo rule ask: Bash(gh release *)") +prefix_rule(pattern=["npm","publish"], decision="prompt", justification="repo rule ask: Bash(npm publish *)") +prefix_rule(pattern=["pnpm","publish"], decision="prompt", justification="repo rule ask: Bash(pnpm publish *)") +prefix_rule(pattern=["yarn","npm","publish"], decision="prompt", justification="repo rule ask: Bash(yarn npm publish *)") +prefix_rule(pattern=["git","push","-f"], decision="prompt", justification="repo rule ask: Bash(git push -f *)") +prefix_rule(pattern=["gh","pr","merge"], decision="prompt", justification="repo rule ask: Bash(gh pr merge *)") +prefix_rule(pattern=["gh","pr","ready"], decision="prompt", justification="repo rule ask: Bash(gh pr ready *)") +prefix_rule(pattern=["git","push"], decision="allow", justification="repo rule allow: Bash(git push *)") +prefix_rule(pattern=["gh","pr","create","--draft"], decision="allow", justification="repo rule allow: Bash(gh pr create --draft *)") diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..cb49f9d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,56 @@ +# AGENTS.md + + + +## Ask first + +Agents ask a person in the current conversation before running these commands or tools in this repository. The rules live in `.claude/settings.json` (the `draft-pr` preset); edit them there and run `configure-agents review` to update this section. + +- `Bash(gh pr comment *)` +- `Bash(gh pr review *)` +- `Bash(gh pr close *)` +- `Bash(gh issue create *)` +- `Bash(gh issue comment *)` +- `Bash(gh issue close *)` +- `Bash(gh release *)` +- `Bash(npm publish *)` +- `Bash(pnpm publish *)` +- `Bash(yarn npm publish *)` +- `Bash(git push -f *)` +- `Bash(git push * -f)` +- `Bash(git push * -f *)` +- `Bash(git push *--force*)` +- `Bash(git push * main)` +- `Bash(git push * master)` +- `Bash(git push *:main)` +- `Bash(git push *:master)` +- `mcp__*github*__create_*` +- `mcp__*github*__add_*` +- `mcp__*github*__update_*` +- `mcp__*github*__merge_*` +- `mcp__*github*__submit_*` +- `mcp__*github*__delete_*` +- `mcp__*github*__push_*` +- `mcp__*slack*__*post*` +- `mcp__*slack*__*send*` +- `Bash(gh pr merge *)` +- `Bash(gh pr ready *)` + +## Never + +Agents never run these in this repository: + +- Nothing is denied outright. + +## Code review + +Follow [REVIEW.md](REVIEW.md) when reviewing changes in this repository. + + + +## Commit and PR guidelines + +- Branch names: a short description of the change, such as `fix/prune-symlinks`. No tool prefixes. +- Commits: Conventional Commits, `type(scope): summary`. +- Merge method: squash or rebase. PRs need a changelog label; CI checks it. +- Releases: `npm run release` (`release-it` with `@release-it-plugins/lerna-changelog`). A maintainer runs it; agents do not. diff --git a/CLAUDE.md b/CLAUDE.md index c62009d..8264071 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -113,3 +113,5 @@ schemas at runtime — vendor a pinned copy with recorded provenance. `src/targets/validation-shared.ts`). - Prettier + eslint enforced by the gate. - Conventional commits. Keep the README CLI reference regenerated. + +Agent permissions, review rules and commit conventions: @AGENTS.md diff --git a/REVIEW.md b/REVIEW.md new file mode 100644 index 0000000..de37544 --- /dev/null +++ b/REVIEW.md @@ -0,0 +1,31 @@ +# REVIEW.md + +Rules for reviewing changes in this repository. People and review agents both follow this file. + +## Always check + +- **Schemas are the source of truth.** Config types come from the zod schemas in `src/schema.ts` through `z.infer`. A config change edits the schema, not `src/types.ts`. +- **Targets come from evidence.** A new target, or a change to a target's layout or manifest, cites the host's official docs or a real plugin it was checked against. Guessed formats are a blocker. +- **The artifact is the seam.** Build, dry run, diff, prune and validate all derive from the in-memory `Artifact`. A change that writes to disk outside it, or makes one of those commands disagree with another, is a blocker. +- **Destructive paths stay guarded.** `prune` and `clean` remove only managed files. A change near them needs a test that proves unmanaged and source files survive. +- **Partials stay narrow.** Only `{{> name}}` tags are substituted, and an unresolved tag fails the build. Do not widen substitution or let it pass silently. +- **Docs follow the CLI.** A change to commands or options regenerates the README CLI reference (`node dist/cli.js docs`). +- **Support floor.** Node 22.12.0 is the supported floor (`engines`), not the Node version the dev tooling pins. + +## Flag only when + +- The change behaves wrongly in a scenario you can describe, emits output a host rejects, or loses an error. Name the scenario and the target. +- A conformance test would pass even if the change were reverted. +- A failure is silent, vague, or blamed on the wrong part. Errors name the file, the field, and the fix. + +## Skip + +- Generated files: `dist/`, `coverage/`, and the generated CLI section of the README. +- Findings in dev-only dependencies. `npm run audit` covers production dependencies on purpose. +- Formatting and lint issues that `npm run check` already handles. + +## Severity + +- **Blocker:** wrong output for a target, a destructive path that can touch unmanaged files, a security problem, or a breaking config change without a migration note. +- **Should fix:** changed behavior without a test, a target change without its source cited, or an unclear name in the public API. +- **Nit:** anything else. Group nits together and never block on them. From e892cd3f28b889c621ca9ef28ca331224b4e4da6 Mon Sep 17 00:00:00 2001 From: Steve Calvert Date: Mon, 12 Oct 2026 17:36:26 -0700 Subject: [PATCH 2/2] style: format .claude/settings.json with Prettier --- .claude/settings.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.claude/settings.json b/.claude/settings.json index 8088f7b..ae43e67 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -1,9 +1,6 @@ { "permissions": { - "allow": [ - "Bash(git push *)", - "Bash(gh pr create --draft *)" - ], + "allow": ["Bash(git push *)", "Bash(gh pr create --draft *)"], "ask": [ "Bash(gh pr comment *)", "Bash(gh pr review *)",