generated from MetaMask/template-snap-monorepo
-
-
Notifications
You must be signed in to change notification settings - Fork 3
feat: add AGENTS.md project guide for agents #272
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,370 @@ | ||
| # AGENTS.md - snap-7715-permissions Project Guide | ||
|
|
||
| This document provides agents with essential information for working on the snap-7715-permissions monorepo. | ||
|
|
||
| ## Project Overview | ||
|
|
||
| This is a monorepo implementing ERC-7715 permissions for MetaMask Snaps. It contains: | ||
|
|
||
| - **@metamask/permissions-kernel-snap** (`packages/permissions-kernel-snap`) - Kernel snap managing the permissions offer registry | ||
| - **@metamask/gator-permissions-snap** (`packages/gator-permissions-snap`) - DeleGator permissions snap that creates delegation accounts | ||
| - **@metamask/shared** (`packages/shared`) - Shared utilities, types, constants, and testing utilities across snaps | ||
| - **Development/test site** (`packages/site`) - Local testing environment for dApp development | ||
|
|
||
| ### Architecture Summary | ||
|
|
||
| - **Kernel Snap**: Manages a `permissions offer registry` listing all permissions a user is willing to grant via ERC-7715 requests | ||
| - **Gator Snap**: Creates DeleGator accounts and enables sites to request ERC-7715 permissions with user review via custom UI dialogs | ||
|
|
||
| ## Technology Stack | ||
|
|
||
| - **Node Version**: 20.x or 22.x (see `.nvmrc`: `^20 || >=22`) | ||
| - **Package Manager**: Yarn 4.10.1 with workspaces | ||
| - **Language**: TypeScript 5.8.3 (strict mode) | ||
| - **Testing**: Jest with @metamask/snaps-jest | ||
| - **Linting**: ESLint 9 (flat config - `eslint.config.mjs`) | ||
| - **Formatting**: Prettier 3.6.2 | ||
| - **Runtime**: MetaMask Snaps (Flask >= 12.14.2) | ||
|
|
||
| ## Package Structure | ||
|
|
||
| ``` | ||
| packages/ | ||
| ├── permissions-kernel-snap/ # Kernel snap (port 8081) | ||
| ├── gator-permissions-snap/ # DeleGator snap (port 8082) | ||
| ├── shared/ # Shared utilities and types | ||
| └── site/ # Development testing site (port 8000) | ||
| ``` | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| 1. **MetaMask Flask**: >= 12.14.2 | ||
| 2. **Node.js**: 20.x or 22.x (use `nvm use` to switch) | ||
| 3. **Yarn**: 4.10.1 (managed via `packageManager` field) | ||
| 4. **Environment variables**: See `.env.example` in each package | ||
|
|
||
| ## Quick Start | ||
|
|
||
| ```bash | ||
| # Install dependencies and set up snap submodules | ||
| yarn prepare:snap | ||
|
|
||
| # Build all packages | ||
| yarn build | ||
|
|
||
| # Start development servers (site on port 8000, snaps on 8081/8082) | ||
| yarn start | ||
| ``` | ||
|
|
||
| ## Build Commands | ||
|
|
||
| ```bash | ||
| # Install dependencies | ||
| yarn install | ||
|
|
||
| # Full setup with snap submodules | ||
| yarn prepare:snap | ||
|
|
||
| # Build all packages (parallel, topological) | ||
| yarn build | ||
|
|
||
| # Build and pack for distribution | ||
| yarn build:pack | ||
|
|
||
| # Update and validate changelogs | ||
| yarn changelog:update | ||
| yarn changelog:validate | ||
| ``` | ||
|
|
||
| ## Development Commands | ||
|
|
||
| ```bash | ||
| # Start all development servers | ||
| yarn start | ||
| # Access at http://localhost:8000/ | ||
| # - permissions-kernel-snap: local:http://localhost:8081 | ||
| # - gator-permissions-snap: local:http://localhost:8082 | ||
|
|
||
| # Run tests (parallel across workspaces) | ||
| yarn test | ||
|
|
||
| # Watch mode for tests | ||
| yarn test --watch | ||
|
|
||
| # Run tests in specific package | ||
| yarn workspace @metamask/gator-permissions-snap test | ||
|
|
||
| # Linting | ||
| yarn lint # Run all linters | ||
| yarn lint:eslint # ESLint only | ||
| yarn lint:fix # Fix linting issues | ||
| yarn lint:misc # Check markdown, JSON, etc. | ||
| ``` | ||
|
|
||
| ## Environment Variables | ||
|
|
||
| All packages throw build-time errors if required env vars are missing. Check `.env.example` in each package. | ||
|
|
||
| ### Common Variables | ||
|
|
||
| | Variable | Description | Package | | ||
| |----------|-------------|---------| | ||
| | `SNAP_ENV` | Environment (development/production) | All | | ||
| | `KERNEL_SNAP_ID` | Snap ID of permissions kernel snap | gator-snap | | ||
| | `STORE_PERMISSIONS_ENABLED` | Feature flag for storage ("true"/"false") | All snaps | | ||
|
|
||
| ### Package-Specific Setup | ||
|
|
||
| Each package requires specific environment variables. See: | ||
| - `packages/permissions-kernel-snap/.env.example` | ||
| - `packages/gator-permissions-snap/.env.example` | ||
| - `packages/site/.env.example` | ||
|
|
||
| ## Code Style and Standards | ||
|
|
||
| ### Formatting Requirements | ||
|
|
||
| - **Prettier** automatically formats code with: | ||
| - Single quotes (`'`) | ||
| - 2-space indentation | ||
| - Trailing commas throughout | ||
| - Quote props as-needed | ||
|
|
||
| All code must be formatted before committing. Run `yarn lint:fix` to auto-fix. | ||
|
|
||
| ### TypeScript Strictness | ||
|
|
||
| The project uses strict TypeScript configuration: | ||
|
|
||
| - `strict: true` - Full type checking | ||
| - `exactOptionalPropertyTypes: true` - No implicit undefined on optional properties | ||
| - `noUncheckedIndexedAccess: true` - Require null checks on indexed access | ||
| - Target: ES2020, Module: Node16 | ||
|
|
||
| ### ESLint Configuration | ||
|
|
||
| The project uses ESLint 9 with flat config (`eslint.config.mjs`). Key rules: | ||
|
|
||
| - No `console.log` in production code | ||
| - No unused variables | ||
| - No untyped `any` without `@ts-expect-error` | ||
| - Imports must be properly sorted | ||
| - JSDoc comments required for public APIs (classes and function declarations) | ||
| - Only allow throwing Snap SDK error objects | ||
|
|
||
| ## Testing Standards | ||
|
|
||
| - **Test files**: Use `*.test.ts` suffix (not `*.spec.ts`) | ||
| - **Structure**: Co-located with source or in `test/` directories | ||
| - **Framework**: Jest with @metamask/snaps-jest | ||
| - **Pattern**: Arrange-Act-Assert | ||
| - **Coverage**: Test happy paths AND error cases | ||
| - **Mocking**: Mock external dependencies (no real HTTP calls) | ||
|
|
||
| Example: | ||
| ```typescript | ||
| describe('parsePermission', () => { | ||
| it('parses valid permission objects', () => { | ||
| const input = { name: 'test', args: [] }; | ||
| const result = parsePermission(input); | ||
| expect(result).toEqual({ name: 'test', args: [] }); | ||
| }); | ||
|
|
||
| it('throws an error with invalid input', () => { | ||
| expect(() => parsePermission({ name: '', args: [] })).toThrow(); | ||
| }); | ||
| }); | ||
| ``` | ||
|
|
||
| > **Important**: `@metamask/snaps-jest` requires the snap to be built first. Always run `yarn build` before testing. | ||
|
|
||
| ## Error Handling | ||
|
|
||
| - Use MetaMask SDK error types: `InternalError`, `InvalidParamsError`, etc. | ||
| - Always provide meaningful error messages with context | ||
| - Never silently fail - log or throw on unexpected conditions | ||
| - Validate all inputs, especially at snap RPC boundaries | ||
| - Reference: https://docs.metamask.io/snaps/how-to/communicate-errors/ | ||
|
|
||
| Example: | ||
| ```typescript | ||
| if (!snapId) { | ||
| throw new InternalError('Snap ID is required'); | ||
| } | ||
| ``` | ||
|
|
||
| ## Type Design | ||
|
|
||
| - Declare types explicitly for all public APIs | ||
| - Use discriminated unions for complex variants | ||
| - Avoid `any` - use `unknown` and narrow types | ||
| - Leverage `const` assertions for literal types | ||
|
|
||
| Example: | ||
| ```typescript | ||
| // Good: Discriminated union | ||
| type Result = | ||
| | { success: true; data: string } | ||
| | { success: false; error: Error }; | ||
|
|
||
| // Bad: Optional properties without discrimination | ||
| type Result = { | ||
| success: boolean; | ||
| data?: string; | ||
| error?: Error; | ||
| }; | ||
| ``` | ||
|
|
||
| ## Snap Development Guidelines | ||
|
|
||
| ### Entry Points | ||
|
|
||
| - Single entry point per snap (e.g., `src/index.ts`) | ||
| - Export `onRpcRequest` handler and optional `onInstall`, `onUpdate`, etc. | ||
| - Use snap manifest (`snap.manifest.ts`) for metadata | ||
|
|
||
| ### RPC Handler Pattern | ||
|
|
||
| ```typescript | ||
| export const onRpcRequest: OnRpcRequestHandler = async (request) => { | ||
| const { method, params } = request; | ||
|
|
||
| switch (method) { | ||
| case 'method1': | ||
| return handleMethod1(params); | ||
| case 'method2': | ||
| return handleMethod2(params); | ||
| default: | ||
| throw new InvalidParamsError(`Unknown method: ${method}`); | ||
| } | ||
| }; | ||
| ``` | ||
|
|
||
| ### State Management | ||
|
|
||
| - Use `snap.request()` with `snap_manageState` for persistence | ||
| - State must be JSON-serializable | ||
| - Keep state minimal - only store what's necessary | ||
| - Always validate state when retrieving it | ||
|
|
||
| ## Code Comments | ||
|
|
||
| - Write comments explaining **why**, not **what** | ||
| - Use JSDoc for public APIs (functions and classes) | ||
| - Keep comments up-to-date with code | ||
|
|
||
| Good example: | ||
| ```typescript | ||
| // Filter out archived accounts to show only active users | ||
| const activeAccounts = accounts.filter(a => !a.archived); | ||
| ``` | ||
|
|
||
| Bad example: | ||
| ```typescript | ||
| const name = user.name; // Get the user's name | ||
| ``` | ||
|
|
||
| ## Git Workflow | ||
|
|
||
| ### Commit Messages | ||
|
|
||
| Follow the conventional commits style: | ||
| - Present tense ("add feature" not "added feature") | ||
| - Reference issues when relevant (#123) | ||
| - Keep first line under 72 characters | ||
|
|
||
| Types: `fix:`, `feat:`, `docs:`, `chore:`, `refactor:`, etc. | ||
|
|
||
| Example: `fix: update intro permission control message for clarity (#269)` | ||
|
|
||
| ### Branches | ||
|
|
||
| - Feature branches: `feat/feature-name` | ||
| - Bug fix branches: `fix/issue-name` | ||
| - Target: `main` branch for PRs | ||
|
|
||
| ### PR Guidelines | ||
|
|
||
| 1. **Must have an open issue** - All PRs must be paired with an issue | ||
| 2. **Clear description** - Explain what and why (not just what) | ||
| 3. **Link issues** - Reference related issues (#123) | ||
| 4. **Test coverage** - Include tests for all new code | ||
| 5. **Follow style guide** - See `docs/styleGuide.md` | ||
| 6. **CI passes** - All linting and tests must pass | ||
|
|
||
| ## Dependency Management | ||
|
|
||
| - Add dependencies with `yarn add` in the appropriate workspace package | ||
| - Prefer existing dependencies in shared packages (`@metamask/shared`) | ||
| - Avoid duplication across workspaces | ||
| - Check root `package.json` `resolutions` for pinned versions | ||
| - Scripts are disabled by default for security; use `lavamoat.allowScripts` | ||
|
|
||
| ## Security Considerations | ||
|
|
||
| 1. **No hardcoded secrets** - Use environment variables | ||
| 2. **Validate all inputs** - Especially RPC parameters | ||
| 3. **Minimize permissions** - Request only necessary snap permissions | ||
| 4. **No arbitrary code execution** - Don't use `eval` or `Function` | ||
| 5. **Sanitize logs** - Never log sensitive data | ||
|
|
||
| ## Performance Guidelines | ||
|
|
||
| 1. **Minimize state size** - Snap state persists to storage | ||
| 2. **Batch RPC calls** - Group related requests to reduce overhead | ||
| 3. **Lazy load dependencies** - Don't import unused modules | ||
| 4. **Efficient serialization** - Keep JSON payloads small | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Build Errors | ||
|
|
||
| - Verify environment variables are set correctly | ||
| - Check Node version matches `.nvmrc` (`nvm use`) | ||
| - Clear yarn cache: `yarn cache clean` | ||
| - Rebuild: `yarn build` | ||
|
|
||
| ### Test Failures | ||
|
|
||
| - Ensure snaps are built before testing: `yarn build` | ||
| - Check test environment variables are configured | ||
| - Run specific test: `yarn test --testNamePattern="test name"` | ||
| - Build specific package: `yarn workspace @metamask/gator-permissions-snap build` | ||
|
|
||
| ### Snap Loading Issues | ||
|
|
||
| - Verify localhost ports (8000, 8081, 8082) are available | ||
| - Check Flask version is 12.14.2+ | ||
| - Clear Flask cache in settings | ||
| - Validate snap manifest is correct | ||
|
|
||
| ## Key Files and Directories | ||
|
|
||
| - `AGENTS.md` - Project guidelines for agents (this file) | ||
| - `CONTRIBUTING.md` - Contribution guidelines | ||
| - `README.md` - Project overview and quick start | ||
| - `docs/styleGuide.md` - Detailed coding style guide | ||
| - `packages/*/src/index.ts` - Snap entry points | ||
| - `packages/*/snap.manifest.ts` - Snap metadata | ||
| - `packages/*/.env.example` - Environment variable examples | ||
| - `tsconfig.json` - Root TypeScript configuration | ||
| - `.prettierrc.js` - Prettier formatting rules | ||
| - `eslint.config.mjs` - ESLint flat config | ||
| - `yarn.lock` - Dependency lockfile | ||
|
|
||
| ## Additional Documentation | ||
|
|
||
| - `docs/addingNewPermissionTypes.md` - How to add new permission types | ||
| - `docs/manifest-management.md` - Snap manifest management | ||
| - `docs/release.md` - Release process | ||
| - `docs/snapPreinstall.md` - Pre-installation setup | ||
| - `packages/gator-permissions-snap/docs/architecture.md` - Gator snap architecture | ||
|
|
||
| ## References | ||
|
|
||
| - [ERC-7715 Specification](https://eip.tools/eip/7715) | ||
| - [ERC-7710 Specification](https://eip.tools/eip/7710) | ||
| - [MetaMask Snaps Docs](https://docs.metamask.io/snaps/) | ||
| - [MetaMask Snaps Repository](https://github.com/MetaMask/snaps) | ||
| - [Delegation Framework](https://github.com/MetaMask/delegation-framework) | ||
| - [MetaMask Snaps Error Handling](https://docs.metamask.io/snaps/how-to/communicate-errors/) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.