mono
CLAUDE.md28 starsChanged 34 days agoMITView on GitHub
DO NOT ADD, REMOVE, OR MODIFY COMMENTS IN CODE — including punctuation and formatting in existing comments. Only touch comments if explicitly asked. After ANY code changes, you MUST run verification (see Verification section). Do not report a task as complete or move on until all checks pass. Leather is a Bitcoin & Stacks wallet — browser extension, mobile app (Expo/React Native), and web app. Turborepo monorepo using pnpm, organized in CLEAN architecture layers. Use the monorepo-navigation skill for detailed…
- Reads credentials
- Installs packages
In this repository5 other files it gives its agents.
- feature-mapSkill
- leather-changelogSkill
- monorepo-navigationSkill
- testing-patternsSkill
- write-extension-e2eSkill
The file
Show its rules and text
We split this CLAUDE.md into the rules it gives an agent
17 rules. About 0 are common, 6 are distinctive, and 11 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
11
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 1
DO NOT ADD, REMOVE, OR MODIFY COMMENTS IN CODE — including punctuation and formatting in existing comments.
- Distinctive: line 3
After ANY code changes, you MUST run verification (see Verification section).
- Very specific: line 23
Use the monorepo-navigation skill for the full decision tree on where new code goes.
- Distinctive: line 64
Don't use enums.
- Very specific: line 65
Default to interface for object shapes.
- Very specific: line 66
Use function declarations for top-level functions and React components.
- Very specific: line 68
Prefer Remeda (keys, entries, pipe, filter, etc.) over Object.keys/Object.entries for typed utilities and non-trivial transforms.
- Very specific: line 70
When a rule removes a type predicate, narrow with an existing guard (isNumber, isDefined, a zod schema) before reaching for flatMap(x => …
- Very specific: line 71
Prefer const over let. Prefer named constants over magic numbers or strings.
- Distinctive: line 72
No nested ternary expressions.
- Very specific: line 73
Use object method shorthand syntax in objects and interfaces ({ foo() {} } not { foo: () => {} }).
- Distinctive: line 81
Never throw in React render paths, reducers, or selectors.
- Very specific: line 90
Use *.spec.ts(x) for tests, co-located next to the file under test.
- Very specific: line 94
Never import from a barrel export (index.ts) within the same package's sub-modules.
- Very specific: line 95
Place initialState in write/slice modules, not shared read modules.
- Distinctive: line 103
Never expose private keys, seeds, or mnemonics in error messages or logs.
- Very specific: line 123
If working on mobile, run pnpm lingui from apps/mobile/ before running verification.
≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
DO NOT ADD, REMOVE, OR MODIFY COMMENTS IN CODE — including punctuation and formatting in existing comments. Only touch comments if explicitly asked.
After ANY code changes, you MUST run verification (see Verification section). Do not report a task as complete or move on until all checks pass.
Claude Instructions
Leather is a Bitcoin & Stacks wallet — browser extension, mobile app (Expo/React Native), and web app.
Architecture
Turborepo monorepo using pnpm, organized in CLEAN architecture layers. Use the monorepo-navigation skill for detailed package structure and decision trees.
Presentation: apps/ (extension, mobile, web), @leather.io/ui, @leather.io/features
Application: @leather.io/queries (React Query), @leather.io/services (orchestration, API calls, DI, caching)
Domain: @leather.io/models (types), @leather.io/bitcoin, @leather.io/stacks
State: @leather.io/state (Redux Toolkit slices for shared state)
Foundation: @leather.io/utils, @leather.io/constants, @leather.io/tokens, @leather.io/crypto
- State management: Redux Toolkit. Extension uses
{feature}.slice.ts; mobile uses{feature}.write.ts(slice + actions) and{feature}.read.ts(selectors + hooks). - Server state: React Query (
@tanstack/react-query). Queries live inpackages/queries/and app-levelsrc/queries/. - Feature flags: LaunchDarkly with
camelCaseflag keys in extension; also used in mobile.
Use the monorepo-navigation skill for the full decision tree on where new code goes.
Development commands
First-time setup:
pnpm i && pnpm buildRun extension:
pnpm devRun web:
pnpm devRun mobile:
cd apps/mobile
pnpm 1password:env:dev # requires 1Password CLI — or ask developer to add EXPO_PUBLIC_LAUNCH_DARKLY to .env
pnpm iosMobile requires an apps/mobile/.env file with EXPO_PUBLIC_LAUNCH_DARKLY set. Run pnpm 1password:env:dev to generate it, or ask the developer to provide the LaunchDarkly key.
React Native / Expo
- Mobile app uses Expo with local prebuild + Fastlane on GitHub runners (no EAS Build, no EAS Update, no @expo/fingerprint).
- SDK upgrades: check the official upgrade guide for deprecated/renamed APIs before starting.
- Clear bundler cache:
npx expo start --dev-client --clear. BUILD_TARGETenv var controls platform builds:mobile,extension, orweb. Unset builds everything.
Code style
- Don't use enums.
- Default to
interfacefor object shapes. Name component propsComponentNameProps. - Use
functiondeclarations for top-level functions and React components. Arrow functions for callbacks only. - Destructure props directly in the function signature.
- Prefer Remeda (
keys,entries,pipe,filter, etc.) overObject.keys/Object.entriesfor typed utilities and non-trivial transforms. Use native methods for trivial cases. - No
ascasts,!non-null assertions, orany. Use runtime checks, type guards, orunknownwith narrowing. - When a rule removes a type predicate, narrow with an existing guard (
isNumber,isDefined, a zod schema) before reaching forflatMap(x => cond ? [x] : []). - Prefer
constoverlet. Prefer named constants over magic numbers or strings. - No nested ternary expressions.
- Use object method shorthand syntax in objects and interfaces (
{ foo() {} }not{ foo: () => {} }). - camelCase for file-level constants; SCREAMING_SNAKE_CASE in the constants package or
constants.tsfiles. - The per-package
eslint-suppressions.jsonfiles and.dependency-cruiser-known-violations.jsonare a frozen baseline of pre-existing violations. Never runeslint --suppress-allor regenerate the known-violations file, and never add entries by hand. Entries only go away by fixing the code (theneslint --prune-suppressionsin that package).
Error handling
throwis acceptable for genuinely invalid states (wrong keychain type, missing required config).- For expected failure paths (user input, optional lookups), prefer returning
null,undefined, or typed result objects. - Never throw in React render paths, reducers, or selectors.
- In React render paths: use error boundaries for unexpected errors; return
nullor fallback UI for expected empty states.
File naming
- Kebab-case file names (e.g.,
alternate-header-layout.tsx). - Platform suffixes for cross-platform code:
.web.tsx,.native.tsx,.shared.ts. - Convention-named config files are exempt (e.g.,
babel.config.cjs,tsconfig.json). - No
index.ts(x)except barrel exports from library packages or file-based router requirements. - Use
*.spec.ts(x)for tests, co-located next to the file under test.
Circular dependencies
- Never import from a barrel export (
index.ts) within the same package's sub-modules. - Place
initialStatein write/slice modules, not shared read modules. - Metro require cycle warnings are bugs to fix, not warnings to ignore.
- Concrete anti-pattern: slice → utils → store → slice. Break by keeping
initialStatein write/slice files and never importing fromstore/index.tswithin slices.
Security
- Sanitize HTML from external sources (NFT metadata, collectible descriptions) before rendering.
- Validate responses from IPFS gateways and untrusted origins.
- Never expose private keys, seeds, or mnemonics in error messages or logs.
Commits
- Conventional commits format with scope:
feat(mobile),refactor(web),fix(utils). - Imperative language. No body unless explicitly asked.
- Branches and PRs are always based against
dev, notmain.
Verification
You MUST run these after any code changes. Do not consider a task complete until they pass:
pnpm format
pnpm lint
pnpm typecheck
pnpm knip
pnpm --filter @leather.io/extension lint:unused-exportsIf working on mobile, run pnpm lingui from apps/mobile/ before running verification.
For faster feedback in a specific package:
pnpm --filter @leather.io/{package} lint
pnpm --filter @leather.io/{package} typecheckTooling
- Turborepo +
pnpm. - Vitest for unit/integration tests. Use the
testing-patternsskill for conventions. - Playwright for E2E tests (extension and web). Sleeps,
networkidle,waitForSelectorand raw locators are lint errors in both suites. For the extension use thewrite-extension-e2eskill: page-object actions own their readiness waits. Avoidforce: true— it hides accessibility issues. Never nest interactive elements.
Common tasks
- Add a UI component →
@leather.io/ui, use themonorepo-navigationskill - Add a Redux slice → Extension:
{feature}.slice.ts; Mobile:{feature}.write.ts+{feature}.read.ts - Add a React Query hook →
packages/queries/or app-levelsrc/queries/ - Run a single package's tests →
pnpm --filter @leather.io/{package} test:unit - Add or fix an extension E2E test →
apps/extension/tests, use thewrite-extension-e2eskill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

