This file provides essential information for Claude AI (and other AI assistants) working with the Porto codebase.
- GitHub MCP:
mcp__github__*functions (authenticated, no rate limits) - GitHub CLI:
ghcommands (authenticated via CLI) - NEVER: Direct API calls, web scraping, or unauthenticated requests
✅ Correct: mcp__github__get_pull_request or gh pr view
❌ Wrong: Direct API calls to api.github.com
- You are allowed to open pull requests for this repository.
- Always use
mcp__github__create_pull_requestorgh pr createto create pull requests.
Porto is a Next-Generation Account Stack for Ethereum that provides a secure, scalable, and user-friendly account system. It's built as a TypeScript monorepo with multiple integrations and applications.
- Docker:
>= 27.0.0 - Playwright:
>= 1.51 - Foundry:
>= 1
pnpm install # Install dependenciespnpm build # Build the core library
pnpm dev # Link library & run dev servers (playground, dialog, id)
pnpm dev:anvil # Run `pnpm dev` with local Relay and Anvil services
pnpm dev:wagmi # Run `pnpm dev` with wagmi playgroundfoundryup --install nightly # Foundry setup
pnpm build:contracts # Build Contracts with Foundry (optional)
pnpm build:anvil-state # Build Anvil State (optional)
pnpm test # Run default test suite with Vitest
pnpm test:browser # Run browser-based tests (Chromium, Firefox)pnpm check # Run Biome linter and formatter
pnpm check:types # Type checking across all packages
pnpm check:build # Validate build outputs with publint and attw
pnpm check:size # Check bundle size limits
pnpm check:repo # Check repository structure with sherif
pnpm check:knip # Check for unused dependencies with knipfoundryup --install nightly # Foundry setup
# Account contracts
forge build --config-path ./contracts/account/foundry.toml
forge test --config-path ./contracts/account/foundry.toml
# Demo contracts
forge build --config-path ./contracts/demo/foundry.toml
forge test --config-path ./contracts/demo/foundry.tomlapps/: Applicationscontracts/: Contracts- The Porto Account contracts are a submodule under the
account/directory
- The Porto Account contracts are a submodule under the
src/:portolibrary source- Files are represented as modules
- Files (modules) that are not exposed to the public API are stored in an
internal/directory
scripts/: Development scriptstest/: Test configuration and utilities
viem- TypeScript Interface for Ethereumwagmi- React Hooks for Ethereumox- Standard Library for Ethereumeffect/schema- Runtime schema validation
Porto- Main stateful Porto module that links together all other modulesChains- Supported Porto chainsDialog- Dialog instancesMessenger- Cross-document communicationMode- Account orchestration mode (e.g.dialog,relay,contract)Storage- Storage interfacesRpcSchema- RPC method schemas and types- Internal modules are stored in an
internal/directory
Account- Viem Account abstraction for Porto AccountsKey- Account key management and cryptographic operations (e.g.secp256k1,p256,webauthn-p256)ContractActions- Actions for the Ithaca Account contract.RelayActions- Actions for the RelayRelayClient- Client helpers for the RelayWalletActions- Actions for the Porto Dialog (EIP-1193 Provider)WalletClient- Client helpers for the Porto Dialog (EIP-1193 Provider)
Actions- Wagmi ActionsConnector- Wagmi ConnectorHooks- React HooksQuery- Wagmi Query utilities
docs/- Documentation site for the SDK (library), Relay and Contractsdialog/- Dialog application (id.porto.sh/dialog)playground/- Development playgroundid/- Account management application (id.porto.sh)wagmi/- Wagmi development playgroundverify/- Application verification worker
account/- Core account abstraction contractsdemo/- Demo and example contracts
- Create a feature branch: Against
main, namedclaude/feature-name - Develop features: Ensure to add any relevant tests for new functionality
- Run tests:
pnpm testandpnpm test:browser - Check code quality:
pnpm check - Build and validate:
pnpm build && pnpm check:build - Add changeset: If any public API or behavioral changes were made to the library (
src/), add a changeset withpnpm changeset. Changesets should use past tense verbs (e.g.Added new feature). Any breaking changes should be noted with a**Breaking:**prefix with a description of how to migrate. - Submit a PR: Ensure PR title is in conventional commit format (e.g.
feat: add new feature) and PR description is detailed
-
You MUST run tests with
CI=true. -
Test file structure must have
describeblocks that are 1:1 with module exports. -
Favor
testoverit. -
Lowercase
testdescriptions (e.g.test('behavior: with foo')) -
testdescriptions should be prefixed with categorytest('behavior: ...'): Behavioral teststest('error: ...'): Error teststest('param: ...'): Parameter validation teststest('misc: ...'): Miscellaneous tests (doesn't fit into above categories)
-
Don't use "should" in test descriptions, just use the verb.
-
Tests must be sorted as such:
test('param: ...')test('behavior: ...')test('error: ...')test('misc: ...')
-
Tests must prefer inline snapshots (
expect(foo).toMatchInlineSnapshot()) over direct assertions. -
For testing multiple similar cases, use
test.each()instead of loops or repeated test blocks:test.each([ { input: 'case1', expected: 'result1' }, { input: 'case2', expected: 'result2' }, ])('behavior: handles $input', ({ input, expected }) => { const result = myFunction(input) expect(result).toBe(expected) })
-
For encoding tests, use
Schema.encodeSync()directly instead ofdecodeUnknownSync -> encodeSync:// ✅ Good: Test encoding directly test('behavior: encodes BigInt to hex', () => { const encoded = Schema.encodeSync(MySchema)({ value: 255n }) expect(encoded).toEqual({ value: '0xff' }) }) // ❌ Bad: Unnecessary decode step test('behavior: encodes BigInt to hex', () => { const decoded = Schema.decodeUnknownSync(MySchema)({ value: '0xff' }) const encoded = Schema.encodeSync(MySchema)(decoded) expect(encoded).toEqual({ value: '0xff' }) })
- All tests must pass (
pnpm test && pnpm test:browser) - Code must be properly formatted (
pnpm check) - Types must be valid (
pnpm check:types) - Build must succeed (
pnpm build) - Bundle size limits must be respected (
pnpm check:size) - No unused dependencies (
pnpm check:knip)
AI Assistants must follow the PR template:
### Summary
<!-- Brief summary of the PR. -->
### Details
<!-- Detailed list of changes in bullet point format. -->
### Areas Touched
<!--
Contextual list of areas of the project touched.
Example:
- Dialog (`apps/dialog`)
- Documentation (`apps/docs`)
- ID Web App (`apps/id`)
- `porto` Library (`src/`)
-->When writing or editing documentation files, follow these style guidelines:
- ✅ "The Porto SDK is a TypeScript library designed for Applications and Wallets"
- ✅ "Porto can be used in conjunction with Wagmi"
- ✅ "This will internally inject a Porto instance"
- ❌ "We designed Porto to..." or "Our SDK allows you to..."
When giving direct instructions to developers, use second person:
- ✅ "You can get started with Porto by creating a new instance"
- ✅ "After you have set up Wagmi, you can set up Porto"
Never use "we," "our," or "I" in technical documentation:
- ❌ "We implemented it, ran it for weeks..."
- ✅ "PREP was implemented and ran for a number of weeks"
- ❌ "we don't want to think about it"
- ✅ "this adds unnecessary complexity"
- ❌ "We do not really care about..."
- ✅ "The provable resource-lock capabilities are not prioritized..."
Before (First Person):
We implemented PREP and ran it for weeks, evaluated the pros/cons and we didn't think it was worth it. We replaced it with an ephemeral private key approach.After (Third Person):
PREP was implemented and ran for a number of weeks. After evaluating the pros/cons, it was decided that the pattern did not meet the needs of the Porto Stack. It was replaced with an ephemeral private key approach.When writing changelog entries, follow these guidelines:
- Sentences lead with verbs such as “Customize…”, “Automatically route…”, “Build and deploy…”, “Click on…”. This keeps the copy action-oriented and user-focused.
- Larger narrative intros use “we” (“Today, we’re launching Porto…”) while instruction paragraphs pivot to second person (“You’ll see your own personalized feed…”). The mix is friendly yet authoritative.
- Each feature gets 1-3 tight paragraphs that start with the user benefit before diving into detail. Jargon is kept product-specific and is usually explained in one line (e.g., “hybrid semantic search combines AI vector embeddings with keyword matching”).
- Big releases open with a bit of storytelling or a rhetorical setup (e.g., “Every product has bugs. More than we can ever fix… Polishing Season is about turning that ‘someday’ into ‘today’”). These break the terseness and add personality.
- Present tense dominates; sentences are short, rarely exceed two clauses.
- Use clear, concise language
- Maintain technical accuracy while improving readability
- Reference specific code with inline formatting or code blocks
- Include relevant file paths and line numbers when applicable
- Use passive voice when appropriate to maintain objectivity
- @claude should Always wrap PR review comments in
<details>tags - Use descriptive summary text in the
<summary>tag - This improves PR browsability by allowing users to easily scan through activity without long review comments cluttering the view
Example format:
<details>
<summary>🔍 Code Review: [Brief description]</summary>
[Your detailed review comments here]
</details>This file should be updated when major architectural changes are made to the codebase.
- You MUST use
pnpm, and you MUST NOT use any other package manager (npm, etc).