Skip to content

Commit 4ade350

Browse files
Improve structure
1 parent db7c3ce commit 4ade350

File tree

1 file changed

+61
-41
lines changed

1 file changed

+61
-41
lines changed

AGENTS.md

Lines changed: 61 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,37 @@ snaps-simulation
136136
snaps-jest
137137
```
138138

139+
## Key Architectural Concepts
140+
141+
### SES and Compartments
142+
143+
Snaps run in [SES (Secure EcmaScript)](https://github.com/endojs/endo/tree/master/packages/ses) compartments for isolation. The compartment limits access to globals.
144+
145+
### Permission System
146+
147+
The platform uses `PermissionController` from `@metamask/permission-controller` extensively:
148+
149+
- **Subjects**: Websites, Snaps, or extensions that request permissions
150+
- **Targets**: JSON-RPC methods or endowments being permissioned
151+
- **Restricted methods**: JSON-RPC methods that require permission to call (e.g., `snap_getBip32Entropy`)
152+
- **Permitted methods**: JSON-RPC methods available without special permission (e.g., `wallet_requestSnaps`). These generally do not pass through the `PermissionController`.
153+
- **Endowment**: Capability granted to a Snap (e.g., `endowment:network-access`). May grant access to JavaScript globals.
154+
- **Caveats**: Constraints that attenuate what a permission grants (e.g., limiting derivation paths)
155+
- **Caveat mappers**: Functions that convert manifest values to caveat objects
156+
157+
### JSON-RPC Flow
158+
159+
Requests flow through a middleware stack in `json-rpc-engine`. Each connection (dapp or Snap) gets its own engine instance. The permission middleware checks authorization before allowing restricted method calls.
160+
161+
### Execution Flow
162+
163+
1. **SnapController** receives a request and starts the Snap if needed
164+
2. **ExecutionService** creates an execution environment (iframe, worker, etc.)
165+
3. **ExecutionEnvironment** sets up SES compartment with allowed endowments
166+
4. Snap code is evaluated in the compartment
167+
5. Exported handlers are registered and can receive requests
168+
6. Responses are validated as JSON-serializable before returning
169+
139170
## Naming Conventions
140171

141172
### File Naming
@@ -161,13 +192,12 @@ snaps-jest
161192

162193
### Function Naming
163194

164-
| Purpose | Pattern | Example |
165-
| ------------- | -------------------- | ------------------------------ |
166-
| Factory | `get[Type]Object` | `getPersistedSnapObject()` |
167-
| Type guard | `is[Type]` | `isCronjobSpecification()` |
168-
| Creator | `create[Thing]` | `createSnapComponent()` |
169-
| Handler | `on[Action]` | `onTransaction`, `onSignature` |
170-
| Caveat mapper | `[type]CaveatMapper` | `snapIdsCaveatMapper()` |
195+
| Purpose | Pattern | Example |
196+
| ---------- | ----------------- | ------------------------------ |
197+
| Factory | `get[Type]Object` | `getPersistedSnapObject()` |
198+
| Type guard | `is[Type]` | `isCronjobSpecification()` |
199+
| Creator | `create[Thing]` | `createSnapComponent()` |
200+
| Handler | `on[Action]` | `onTransaction`, `onSignature` |
171201

172202
### Test Utilities
173203

@@ -177,29 +207,6 @@ snaps-jest
177207
| Factory helper | `get[Type]Object()` | `getSnapObject()`, `getPersistedSnapObject()` |
178208
| Directory | `__mocks__/`, `__fixtures__/` | `__mocks__/fs.ts` |
179209

180-
## Domain Vocabulary
181-
182-
### Snap Lifecycle
183-
184-
- **SnapId**: Unique identifier (e.g., `npm:@metamask/example-snap`)
185-
- **SnapStatus**: Lifecycle state (`Stopped`, `Running`, `Crashed`)
186-
- **SnapManifest**: Configuration file (`snap.manifest.json`)
187-
- **TruncatedSnap**: Lightweight Snap representation
188-
- **PersistedSnap**: Full Snap data for storage
189-
190-
### Permission System
191-
192-
- **Caveat**: Constraint on a permission
193-
- **Endowment**: Capability granted to a Snap (e.g., `endowment:network-access`). May grant access to JavaScript globals.
194-
- **Restricted**: JSON-RPC method requiring permission
195-
- **Permitted**: Publicly accessible JSON-RPC method
196-
197-
### Execution
198-
199-
- **ExecutionEnvironment**: Runtime context (iframe, webview, worker)
200-
- **Job**: Execution task with Snap ID, streams, and JSON-RPC engine
201-
- **Endowments**: APIs available in Snap context
202-
203210
## Adding New Platform Features
204211

205212
When implementing a new Snaps Platform feature (e.g., a new permission, endowment, or RPC method), include:
@@ -250,8 +257,23 @@ See `packages/examples/packages/multichain-provider/` for a complete example.
250257

251258
## Code Guidelines
252259

260+
### General
261+
262+
- Packages use `workspace:^` for internal dependencies
263+
- Build uses `ts-bridge` (not tsc directly) to produce ESM and CJS outputs
264+
- Tests use Jest with SWC for transformation; some packages also have Vitest browser tests
265+
- JSX components use `@metamask/snaps-sdk/jsx` with automatic runtime
266+
- Coverage threshold is 100% by default (some packages override this)
267+
- Workspace package names use `@metamask/` scope (e.g., `@metamask/snaps-controllers`, not the directory name `snaps-controllers`)
268+
- Use uppercase "Snap" (not "snap") in comments and documentation when referring to MetaMask Snaps
269+
- Document all functions, classes, and types with JSDoc
270+
- Use `@metamask/superstruct` for runtime validation of data structures, RPC parameters, and API inputs/outputs
271+
- Define a `[Type]Struct` and infer the TypeScript type from it: `type MyType = Infer<typeof MyTypeStruct>`
272+
- Validate early at system boundaries (RPC handlers, external data) rather than deep in business logic
273+
253274
### Controllers
254275

276+
- Controllers are generally used whenever we need to store state in the MetaMask clients
255277
- Controller classes should extend `BaseController`
256278
- Controllers must have state; stateless logic belongs in services
257279
- Define public messenger types with actions and events
@@ -261,16 +283,14 @@ See `packages/examples/packages/multichain-provider/` for a complete example.
261283
### Exports
262284

263285
- Each package has an `index.ts` that defines all public exports
264-
- Use barrel exports (`export * from './module'`)
265-
- Superstruct validators define both the struct and inferred type together
286+
- Some packages have platform-specific entry points (e.g., `@metamask/snaps-utils/node`, `@metamask/snaps-controllers/node`, `@metamask/snaps-controllers/react-native`) for platform-specific APIs that shouldn't be bundled for other environments
266287

267-
### General
288+
## Further Reading
268289

269-
- Packages use `workspace:^` for internal dependencies
270-
- Build uses `ts-bridge` (not tsc directly) to produce ESM and CJS outputs
271-
- Tests use Jest with SWC for transformation; some packages also have Vitest browser tests
272-
- JSX components use `@metamask/snaps-sdk/jsx` with automatic runtime
273-
- Coverage threshold is 100% by default (some packages override this)
274-
- Workspace package names use `@metamask/` scope (e.g., `@metamask/snaps-controllers`, not the directory name `snaps-controllers`)
275-
- Use uppercase "Snap" (not "snap") in comments and documentation when referring to MetaMask Snaps
276-
- Document all functions, classes, and types with JSDoc
290+
See `docs/` for detailed platform internals:
291+
292+
- `docs/internals/architecture.md` — System overview with sequence diagrams
293+
- `docs/internals/permissions.md` — Permission system deep dive
294+
- `docs/internals/execution.md` — SES sandboxing and endowments
295+
- `docs/internals/json-rpc.md` — JSON-RPC middleware stack
296+
- `docs/internals/platform/` — Individual component documentation

0 commit comments

Comments
 (0)