Skip to content

Commit dad2565

Browse files
authored
feat: add AGENTS.md project guide for agents (#272)
* feat: add AGENTS.md project guide for agents * docs: optimize AGENTS.md based on PR review feedback - Remove "should" from test descriptions for clearer assertions - Add directory paths for packages in Project Overview - Replace in-memory caching guideline with batching RPC calls for better relevance Addresses reviewer comments from PR #272 * docs: enhance AGENTS.md with detailed project structure and setup instructions
1 parent d0cff8f commit dad2565

File tree

1 file changed

+370
-0
lines changed

1 file changed

+370
-0
lines changed

AGENTS.md

Lines changed: 370 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,370 @@
1+
# AGENTS.md - snap-7715-permissions Project Guide
2+
3+
This document provides agents with essential information for working on the snap-7715-permissions monorepo.
4+
5+
## Project Overview
6+
7+
This is a monorepo implementing ERC-7715 permissions for MetaMask Snaps. It contains:
8+
9+
- **@metamask/permissions-kernel-snap** (`packages/permissions-kernel-snap`) - Kernel snap managing the permissions offer registry
10+
- **@metamask/gator-permissions-snap** (`packages/gator-permissions-snap`) - DeleGator permissions snap that creates delegation accounts
11+
- **@metamask/shared** (`packages/shared`) - Shared utilities, types, constants, and testing utilities across snaps
12+
- **Development/test site** (`packages/site`) - Local testing environment for dApp development
13+
14+
### Architecture Summary
15+
16+
- **Kernel Snap**: Manages a `permissions offer registry` listing all permissions a user is willing to grant via ERC-7715 requests
17+
- **Gator Snap**: Creates DeleGator accounts and enables sites to request ERC-7715 permissions with user review via custom UI dialogs
18+
19+
## Technology Stack
20+
21+
- **Node Version**: 20.x or 22.x (see `.nvmrc`: `^20 || >=22`)
22+
- **Package Manager**: Yarn 4.10.1 with workspaces
23+
- **Language**: TypeScript 5.8.3 (strict mode)
24+
- **Testing**: Jest with @metamask/snaps-jest
25+
- **Linting**: ESLint 9 (flat config - `eslint.config.mjs`)
26+
- **Formatting**: Prettier 3.6.2
27+
- **Runtime**: MetaMask Snaps (Flask >= 12.14.2)
28+
29+
## Package Structure
30+
31+
```
32+
packages/
33+
├── permissions-kernel-snap/ # Kernel snap (port 8081)
34+
├── gator-permissions-snap/ # DeleGator snap (port 8082)
35+
├── shared/ # Shared utilities and types
36+
└── site/ # Development testing site (port 8000)
37+
```
38+
39+
## Prerequisites
40+
41+
1. **MetaMask Flask**: >= 12.14.2
42+
2. **Node.js**: 20.x or 22.x (use `nvm use` to switch)
43+
3. **Yarn**: 4.10.1 (managed via `packageManager` field)
44+
4. **Environment variables**: See `.env.example` in each package
45+
46+
## Quick Start
47+
48+
```bash
49+
# Install dependencies and set up snap submodules
50+
yarn prepare:snap
51+
52+
# Build all packages
53+
yarn build
54+
55+
# Start development servers (site on port 8000, snaps on 8081/8082)
56+
yarn start
57+
```
58+
59+
## Build Commands
60+
61+
```bash
62+
# Install dependencies
63+
yarn install
64+
65+
# Full setup with snap submodules
66+
yarn prepare:snap
67+
68+
# Build all packages (parallel, topological)
69+
yarn build
70+
71+
# Build and pack for distribution
72+
yarn build:pack
73+
74+
# Update and validate changelogs
75+
yarn changelog:update
76+
yarn changelog:validate
77+
```
78+
79+
## Development Commands
80+
81+
```bash
82+
# Start all development servers
83+
yarn start
84+
# Access at http://localhost:8000/
85+
# - permissions-kernel-snap: local:http://localhost:8081
86+
# - gator-permissions-snap: local:http://localhost:8082
87+
88+
# Run tests (parallel across workspaces)
89+
yarn test
90+
91+
# Watch mode for tests
92+
yarn test --watch
93+
94+
# Run tests in specific package
95+
yarn workspace @metamask/gator-permissions-snap test
96+
97+
# Linting
98+
yarn lint # Run all linters
99+
yarn lint:eslint # ESLint only
100+
yarn lint:fix # Fix linting issues
101+
yarn lint:misc # Check markdown, JSON, etc.
102+
```
103+
104+
## Environment Variables
105+
106+
All packages throw build-time errors if required env vars are missing. Check `.env.example` in each package.
107+
108+
### Common Variables
109+
110+
| Variable | Description | Package |
111+
|----------|-------------|---------|
112+
| `SNAP_ENV` | Environment (development/production) | All |
113+
| `KERNEL_SNAP_ID` | Snap ID of permissions kernel snap | gator-snap |
114+
| `STORE_PERMISSIONS_ENABLED` | Feature flag for storage ("true"/"false") | All snaps |
115+
116+
### Package-Specific Setup
117+
118+
Each package requires specific environment variables. See:
119+
- `packages/permissions-kernel-snap/.env.example`
120+
- `packages/gator-permissions-snap/.env.example`
121+
- `packages/site/.env.example`
122+
123+
## Code Style and Standards
124+
125+
### Formatting Requirements
126+
127+
- **Prettier** automatically formats code with:
128+
- Single quotes (`'`)
129+
- 2-space indentation
130+
- Trailing commas throughout
131+
- Quote props as-needed
132+
133+
All code must be formatted before committing. Run `yarn lint:fix` to auto-fix.
134+
135+
### TypeScript Strictness
136+
137+
The project uses strict TypeScript configuration:
138+
139+
- `strict: true` - Full type checking
140+
- `exactOptionalPropertyTypes: true` - No implicit undefined on optional properties
141+
- `noUncheckedIndexedAccess: true` - Require null checks on indexed access
142+
- Target: ES2020, Module: Node16
143+
144+
### ESLint Configuration
145+
146+
The project uses ESLint 9 with flat config (`eslint.config.mjs`). Key rules:
147+
148+
- No `console.log` in production code
149+
- No unused variables
150+
- No untyped `any` without `@ts-expect-error`
151+
- Imports must be properly sorted
152+
- JSDoc comments required for public APIs (classes and function declarations)
153+
- Only allow throwing Snap SDK error objects
154+
155+
## Testing Standards
156+
157+
- **Test files**: Use `*.test.ts` suffix (not `*.spec.ts`)
158+
- **Structure**: Co-located with source or in `test/` directories
159+
- **Framework**: Jest with @metamask/snaps-jest
160+
- **Pattern**: Arrange-Act-Assert
161+
- **Coverage**: Test happy paths AND error cases
162+
- **Mocking**: Mock external dependencies (no real HTTP calls)
163+
164+
Example:
165+
```typescript
166+
describe('parsePermission', () => {
167+
it('parses valid permission objects', () => {
168+
const input = { name: 'test', args: [] };
169+
const result = parsePermission(input);
170+
expect(result).toEqual({ name: 'test', args: [] });
171+
});
172+
173+
it('throws an error with invalid input', () => {
174+
expect(() => parsePermission({ name: '', args: [] })).toThrow();
175+
});
176+
});
177+
```
178+
179+
> **Important**: `@metamask/snaps-jest` requires the snap to be built first. Always run `yarn build` before testing.
180+
181+
## Error Handling
182+
183+
- Use MetaMask SDK error types: `InternalError`, `InvalidParamsError`, etc.
184+
- Always provide meaningful error messages with context
185+
- Never silently fail - log or throw on unexpected conditions
186+
- Validate all inputs, especially at snap RPC boundaries
187+
- Reference: https://docs.metamask.io/snaps/how-to/communicate-errors/
188+
189+
Example:
190+
```typescript
191+
if (!snapId) {
192+
throw new InternalError('Snap ID is required');
193+
}
194+
```
195+
196+
## Type Design
197+
198+
- Declare types explicitly for all public APIs
199+
- Use discriminated unions for complex variants
200+
- Avoid `any` - use `unknown` and narrow types
201+
- Leverage `const` assertions for literal types
202+
203+
Example:
204+
```typescript
205+
// Good: Discriminated union
206+
type Result =
207+
| { success: true; data: string }
208+
| { success: false; error: Error };
209+
210+
// Bad: Optional properties without discrimination
211+
type Result = {
212+
success: boolean;
213+
data?: string;
214+
error?: Error;
215+
};
216+
```
217+
218+
## Snap Development Guidelines
219+
220+
### Entry Points
221+
222+
- Single entry point per snap (e.g., `src/index.ts`)
223+
- Export `onRpcRequest` handler and optional `onInstall`, `onUpdate`, etc.
224+
- Use snap manifest (`snap.manifest.ts`) for metadata
225+
226+
### RPC Handler Pattern
227+
228+
```typescript
229+
export const onRpcRequest: OnRpcRequestHandler = async (request) => {
230+
const { method, params } = request;
231+
232+
switch (method) {
233+
case 'method1':
234+
return handleMethod1(params);
235+
case 'method2':
236+
return handleMethod2(params);
237+
default:
238+
throw new InvalidParamsError(`Unknown method: ${method}`);
239+
}
240+
};
241+
```
242+
243+
### State Management
244+
245+
- Use `snap.request()` with `snap_manageState` for persistence
246+
- State must be JSON-serializable
247+
- Keep state minimal - only store what's necessary
248+
- Always validate state when retrieving it
249+
250+
## Code Comments
251+
252+
- Write comments explaining **why**, not **what**
253+
- Use JSDoc for public APIs (functions and classes)
254+
- Keep comments up-to-date with code
255+
256+
Good example:
257+
```typescript
258+
// Filter out archived accounts to show only active users
259+
const activeAccounts = accounts.filter(a => !a.archived);
260+
```
261+
262+
Bad example:
263+
```typescript
264+
const name = user.name; // Get the user's name
265+
```
266+
267+
## Git Workflow
268+
269+
### Commit Messages
270+
271+
Follow the conventional commits style:
272+
- Present tense ("add feature" not "added feature")
273+
- Reference issues when relevant (#123)
274+
- Keep first line under 72 characters
275+
276+
Types: `fix:`, `feat:`, `docs:`, `chore:`, `refactor:`, etc.
277+
278+
Example: `fix: update intro permission control message for clarity (#269)`
279+
280+
### Branches
281+
282+
- Feature branches: `feat/feature-name`
283+
- Bug fix branches: `fix/issue-name`
284+
- Target: `main` branch for PRs
285+
286+
### PR Guidelines
287+
288+
1. **Must have an open issue** - All PRs must be paired with an issue
289+
2. **Clear description** - Explain what and why (not just what)
290+
3. **Link issues** - Reference related issues (#123)
291+
4. **Test coverage** - Include tests for all new code
292+
5. **Follow style guide** - See `docs/styleGuide.md`
293+
6. **CI passes** - All linting and tests must pass
294+
295+
## Dependency Management
296+
297+
- Add dependencies with `yarn add` in the appropriate workspace package
298+
- Prefer existing dependencies in shared packages (`@metamask/shared`)
299+
- Avoid duplication across workspaces
300+
- Check root `package.json` `resolutions` for pinned versions
301+
- Scripts are disabled by default for security; use `lavamoat.allowScripts`
302+
303+
## Security Considerations
304+
305+
1. **No hardcoded secrets** - Use environment variables
306+
2. **Validate all inputs** - Especially RPC parameters
307+
3. **Minimize permissions** - Request only necessary snap permissions
308+
4. **No arbitrary code execution** - Don't use `eval` or `Function`
309+
5. **Sanitize logs** - Never log sensitive data
310+
311+
## Performance Guidelines
312+
313+
1. **Minimize state size** - Snap state persists to storage
314+
2. **Batch RPC calls** - Group related requests to reduce overhead
315+
3. **Lazy load dependencies** - Don't import unused modules
316+
4. **Efficient serialization** - Keep JSON payloads small
317+
318+
## Troubleshooting
319+
320+
### Build Errors
321+
322+
- Verify environment variables are set correctly
323+
- Check Node version matches `.nvmrc` (`nvm use`)
324+
- Clear yarn cache: `yarn cache clean`
325+
- Rebuild: `yarn build`
326+
327+
### Test Failures
328+
329+
- Ensure snaps are built before testing: `yarn build`
330+
- Check test environment variables are configured
331+
- Run specific test: `yarn test --testNamePattern="test name"`
332+
- Build specific package: `yarn workspace @metamask/gator-permissions-snap build`
333+
334+
### Snap Loading Issues
335+
336+
- Verify localhost ports (8000, 8081, 8082) are available
337+
- Check Flask version is 12.14.2+
338+
- Clear Flask cache in settings
339+
- Validate snap manifest is correct
340+
341+
## Key Files and Directories
342+
343+
- `AGENTS.md` - Project guidelines for agents (this file)
344+
- `CONTRIBUTING.md` - Contribution guidelines
345+
- `README.md` - Project overview and quick start
346+
- `docs/styleGuide.md` - Detailed coding style guide
347+
- `packages/*/src/index.ts` - Snap entry points
348+
- `packages/*/snap.manifest.ts` - Snap metadata
349+
- `packages/*/.env.example` - Environment variable examples
350+
- `tsconfig.json` - Root TypeScript configuration
351+
- `.prettierrc.js` - Prettier formatting rules
352+
- `eslint.config.mjs` - ESLint flat config
353+
- `yarn.lock` - Dependency lockfile
354+
355+
## Additional Documentation
356+
357+
- `docs/addingNewPermissionTypes.md` - How to add new permission types
358+
- `docs/manifest-management.md` - Snap manifest management
359+
- `docs/release.md` - Release process
360+
- `docs/snapPreinstall.md` - Pre-installation setup
361+
- `packages/gator-permissions-snap/docs/architecture.md` - Gator snap architecture
362+
363+
## References
364+
365+
- [ERC-7715 Specification](https://eip.tools/eip/7715)
366+
- [ERC-7710 Specification](https://eip.tools/eip/7710)
367+
- [MetaMask Snaps Docs](https://docs.metamask.io/snaps/)
368+
- [MetaMask Snaps Repository](https://github.com/MetaMask/snaps)
369+
- [Delegation Framework](https://github.com/MetaMask/delegation-framework)
370+
- [MetaMask Snaps Error Handling](https://docs.metamask.io/snaps/how-to/communicate-errors/)

0 commit comments

Comments
 (0)