Skip to content

docs: check in agent rules distilled from past PR reviews - #4174

Open
sea-snake wants to merge 9 commits into
mainfrom
chore/claude-rules
Open

sea-snake wants to merge 9 commits into
mainfrom
chore/claude-rules

Conversation

@sea-snake

@sea-snake sea-snake commented Aug 3, 2026 •

Copy link
Copy Markdown
Contributor

The conventions coding agents follow in this repo have been maintained in a separate repository and symlinked into each developer's working copy. That keeps them invisible to anyone reading this repository, and they drift from the code they describe. Checking them in puts rule changes through code review alongside the code they govern.

The rules are distilled from the review history of this repository: the discussions on all 4,289 pull requests (merged, closed and open) were read and the guidance reviewers gave repeatedly, or stated as a principle, was kept. Each candidate was checked against the current tree; guidance from the lit-html, dfx and selenium era that no longer applies was dropped.

Changes

Organise .claude/rules/ by topic. Each file carries paths: frontmatter where it applies to a subtree, so it only enters an agent's context when those files are in play:

File Applies to Covers
pull-requests.md everything pre-commit checks, scope, titles, descriptions, stacks, CI, reviews
code-style.md everything naming, comments and doc comments, scope, reuse
handle-all-type-variants.md everything exhaustive handling of candid variants, Rust enums, TS unions
security.md src/** bounded resources, authorization, origins, delegations, leaks
backend.md canister crates no trapping, state and await, layering, Rust style, clippy, PocketIC
candid-api.md *.did, interface crate, bindings, docs/ii-spec.mdx API evolution, shape, error design, bindings
stable-memory.md storage, state, upgrade tests record formats, memory indices, migrations, upgrades
frontend.md src/frontend/** design system, Svelte, async and errors, TypeScript, accessibility
i18n-and-copy.md frontend sources, locales translations, <Trans>/$t, UI copy
testing.md tests, Rust sources where coverage goes, assertions that can fail
e2e-testing.md Playwright tests, scripts/dev-e2e* the dev-e2e stack, writing Playwright tests
scripts-and-ci.md scripts/**, .github/**, manifests shell scripts, workflows, dependencies, feature flags

Where review history and the earlier rules disagreed, the rules follow what the code and the most recent reviews do:

  • The no-trap rule names its exceptions: Storable::from_bytes (which cannot return an error) and HTTP outcall transforms, plus deliberate rollback. It adds that returning Err does not roll back earlier writes, so fallible checks run before the first write.
  • Error design: add a variant only when the caller's next step differs; everything else is InternalCanisterError.
  • Comments: names carry meaning and comments explain only what code can't, but constants, new types and non-trivial modules get doc comments.
  • Tests: behaviour is covered in PocketIC and Playwright rather than mocked unit tests, while non-trivial pure functions still get unit or property tests.

This PR's own review:

  • The comment guidance is generalised beyond Tailwind template comments and applies to all code (code-style.md).
  • The "Full-stack mindset" section and the CI polling loop are removed.
  • AI attribution footers ("Generated with Claude") are forbidden in commits, PR descriptions, replies and code.
  • Requesting Copilot on a stacked PR now uses GraphQL requestReviews; the REST call answered 200 but added nobody.

Un-ignore the rules directory in .gitignore: .claude/ becomes .claude/* plus !.claude/rules/, since a directory-level ignore stops git descending. Everything else Claude Code writes there stays ignored.

Reduce CLAUDE.md to an index of the rules directory, and note that FLOWS.mdx is out of date.

These conventions previously lived in a separate repo and were symlinked
into the working copy by a SessionStart hook, so they were invisible to
anyone reading this repository and drifted from the code they describe.
Checking them in puts them under review alongside the code.

Each rule carries `paths:` frontmatter where it applies to a subtree, so
it only enters an agent's context when the files it governs are in play.

Three facts were stale on arrival and are corrected here:

- The e2e rule listed OpenID providers on 11105-11107; a fourth provider
  on 11108 has since been added. It now points at OPENID_PORTS and
  friends in scripts/dev-e2e-setup instead of restating the list.
- It also documented a `sso_discoverable_domains` init arg that no longer
  exists — SSO discovery is domain-based now. Dropped.
- The backend rule hardcoded the arm64-linux PocketIC asset. The release
  ships all four arch/OS combos, so it now says to match the host.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 3, 2026 09:24
@sea-snake
sea-snake requested a review from a team as a code owner August 3, 2026 09:24
@zeropath-ai

zeropath-ai Bot commented Aug 3, 2026 •

Copy link
Copy Markdown

✅ No security or compliance issues detected. Reviewed everything up to 219c7fc.

Security Overview
Detected Code Changes
Change Type Relevant files
Other ► .claude/rules/backend.md
    Add backend Claude rules file for Rust canister code
► .claude/rules/candid-api.md
    Add Candid API Claude rules
► .claude/rules/code-style.md
    Add code style Claude rules
► .claude/rules/e2e-testing.md
    Add E2E testing Claude rules
► .claude/rules/frontend.md
    Add frontend Claude rules
► .claude/rules/handle-all-type-variants.md
    Add exhaustive variant handling Claude rule
► .claude/rules/i18n-and-copy.md
    Add i18n and copy Claude rule
► .claude/rules/pull-requests.md
    Add pull requests Claude guidelines
► .claude/rules/scripts-and-ci.md
    Add scripts and CI Claude guidelines
► .claude/rules/security.md
    Add security Claude guidelines
► .claude/rules/stable-memory.md
    Add stable memory Claude rules
► .claude/rules i18n-and-copy.md
    Duplicate/misformatted entry in rules set (typo)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR checks in AI coding-agent conventions directly into the repository under .claude/rules/ (scoped via paths: frontmatter where appropriate), making them visible in code review and easier to keep in sync with code changes. It also updates repo hygiene so the rules are tracked while other local agent state remains ignored.

Changes:

  • Add five topic-focused rule documents under .claude/rules/ (workflow, exhaustive variant handling, backend/Rust, frontend, and Playwright e2e).
  • Update .gitignore to stop ignoring the entire .claude/ directory and instead ignore everything except .claude/rules/.
  • Reduce CLAUDE.md to an index pointing at the checked-in rule files.

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
CLAUDE.md Converted to a short index of the checked-in agent rule docs.
.gitignore Ignores .claude/* local state while explicitly un-ignoring .claude/rules/ for check-in.
.claude/rules/workflow.md Adds workflow conventions (formatting/linting, PR title/description conventions, CI/review loop guidance).
.claude/rules/handle-all-type-variants.md Adds guidance to handle all union/variant cases across Rust/TS/Candid boundaries.
.claude/rules/backend.md Adds Rust-canister conventions (no traps, clippy flags, PocketIC integration-test setup notes).
.claude/rules/frontend.md Adds frontend conventions (design tokens, component reuse, i18n/Svelte/TS patterns, utilities, UX copy).
.claude/rules/e2e-testing.md Adds Playwright e2e/dev-stack guidance and references to the script-defined OpenID port constants.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@sea-snake
sea-snake requested review from MRmarioruci and aterga August 3, 2026 09:33
Comment thread .claude/rules/frontend.md Resolved
Comment thread .claude/rules/workflow.md Resolved
Comment thread .claude/rules/workflow.md Resolved
Comment thread .claude/rules/workflow.md Resolved
Copilot AI max review requested due to automatic review settings November 11, 2026 12:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread .claude/rules/backend.md Resolved
Comment thread .claude/rules/backend.md Resolved
Comment thread .claude/rules/backend.md Resolved
Comment thread .claude/rules/backend.md Resolved
Comment thread .claude/rules/backend.md Resolved
Comment thread .claude/rules/e2e-testing.md Resolved
Comment thread .claude/rules/e2e-testing.md Resolved
Comment thread .claude/rules/frontend.md Resolved
Comment thread .claude/rules/workflow.md Resolved
Comment thread .claude/rules/workflow.md Resolved
Reorganise .claude/rules/ by topic and add the conventions reviewers have
repeatedly asked for across the repository's merged, closed and open PRs:
code style, security, candid API evolution, stable memory and upgrades,
testing, i18n and copy, and scripts/CI. workflow.md becomes
pull-requests.md.

Address the review on this PR: generalise the comment guidance beyond
Tailwind and apply it to all code, drop the full-stack and CI polling
sections, and forbid AI attribution footers.
Copilot AI max review requested due to automatic review settings November 11, 2026 12:43
@sea-snake sea-snake changed the title docs: check in agent rules under .claude/rules/ docs: check in agent rules distilled from past PR reviews Nov 11, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread .claude/rules/backend.md
- "src/internet_identity_frontend/**"
- "src/internet_identity_interface/**"
- "src/asset_util/**"
- "src/canister_tests/**"
Comment thread .claude/rules/backend.md

- On the IC, returning `Err` commits every write made before it; only a trap rolls back. Run every check that can fail before the first write, and never `?` after a write.
- Every `await` is a commit point and lets other messages run. Re-read and re-check (authorization, existence, generation) anything captured before it; never write back a value loaded before it. A lock or "in progress" flag written before an `await` needs a recovery path.
- Don't check, await, then write (lazy salts, get-or-create with `raw_rand`). Initialize at install, or refuse.
Comment thread .claude/rules/e2e-testing.md Outdated
## Stack gotchas

- With `NO_HOT_RELOAD=1` and `SEPARATE_FRONTEND_CANISTER=1` the browser loads assets from the canister. `.svelte` changes take effect only after `dev-e2e-setup` reinstalls it.
- Re-running `dev-e2e-setup` does not re-apply changed init args to an installed canister. Run `--teardown` first.
Comment thread .claude/rules/pull-requests.md Resolved
- Rust: `cargo fmt`, then `cargo clippy` with the flags in `backend.md`.
- JS/TS/Svelte: `npm run format`, `npm run lint -- --fix`, `npm run check`. CI stops at the first failure, so fix all three.
- After a `.did` change: `npm run generate` (see `candid-api.md`).
- Revert any `src/frontend/src/lib/locales/*.po` diff (see `i18n-and-copy.md`).
Comment thread .claude/rules/security.md
- Parse URLs with `new URL()` / the `url` crate and compare exact origins (`new URL(x).origin === x`). Never concatenate URL parts or use substring checks.
- Match a hostname against an allowlist exactly or on a dot boundary (`h === d || h.endsWith("." + d)`), never a bare `endsWith(d)`.
- Accept only the canonical form of security-relevant input (lowercase origins without default port or userinfo, uncompressed keys); a caller sending another form is refused, not silently normalized. Operator configuration (install args) is canonicalized (trim, ASCII-lowercase) once, before it is persisted.
- Every origin used as an outcall target or derivation input goes through the canonicalizing validator and requires `https`. Plain `http` is allowed only for loopback hosts behind an explicit dev flag.
Comment thread .claude/rules/security.md
## Delegations and keys

- Length-prefix every variable-length field when hashing a seed.
- Keep delegation seeds minimal and justify every input. Set delegation `targets` where the canister signs, and keep them when rebuilding a chain.
Comment thread .claude/rules/security.md

- Length-prefix every variable-length field when hashing a seed.
- Keep delegation seeds minimal and justify every input. Set delegation `targets` where the canister signs, and keep them when rebuilding a chain.
- Delegation lifetimes that cross the IC are at least 5 minutes, because of replica clock drift.
- "src/internet_identity/src/main.rs"
- "src/internet_identity/tests/integration/upgrade.rs"
- "src/internet_identity/tests/integration/rollback.rs"
- "src/internet_identity/stable_memory/**"
Comment on lines +19 to +20
- Stored records are minicbor `#[cbor(map)]` with numeric keys (`#[n(k)]`). Rust field names can be renamed freely; the keys cannot.
- A new field on a stored type must be `Option` or `#[cbor(default)]`. Existing records don't have the key, and a required field traps every read of them. This took staging down once (#4481).
Copilot AI max review requested due to automatic review settings November 11, 2026 12:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

## Stack gotchas

- With `NO_HOT_RELOAD=1` and `SEPARATE_FRONTEND_CANISTER=1` the browser loads assets from the canister. `.svelte` changes take effect only after `dev-e2e-setup` reinstalls it.
- Re-running `dev-e2e-setup` rebuilds a canister only when files in its own directory (or `src/frontend`) are newer than its wasm. Changes to shared crates (`src/internet_identity_interface`, `src/asset_util`) and changed init args are not picked up: run `--teardown` first.
Copilot AI max review requested due to automatic review settings November 11, 2026 14:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot AI max review requested due to automatic review settings November 11, 2026 14:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot AI max review requested due to automatic review settings November 11, 2026 14:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot AI max review requested due to automatic review settings November 11, 2026 15:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants