create-miden-app 1.0.3 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/cli.js +6 -6
  2. package/package.json +1 -6
  3. package/template/.claude/hooks/check-artifacts.sh +45 -0
  4. package/template/.claude/hooks/run-affected-tests.sh +31 -0
  5. package/template/.claude/hooks/typecheck.sh +27 -0
  6. package/template/.claude/settings.json +35 -0
  7. package/template/.claude/skills/frontend-pitfalls/SKILL.md +189 -0
  8. package/template/.claude/skills/frontend-source-guide/SKILL.md +163 -0
  9. package/template/.claude/skills/miden-concepts/SKILL.md +108 -0
  10. package/template/.claude/skills/react-sdk-patterns/SKILL.md +296 -0
  11. package/template/.claude/skills/signer-integration/SKILL.md +158 -0
  12. package/template/.claude/skills/testing-patterns/SKILL.md +177 -0
  13. package/template/.claude/skills/vite-wasm-setup/SKILL.md +128 -0
  14. package/template/.env.example +5 -0
  15. package/template/CLAUDE.md +210 -0
  16. package/template/README.md +53 -14
  17. package/template/create-miden-app/template/.claude/hooks/typecheck.sh +27 -0
  18. package/template/create-miden-app/template/.claude/settings.json +17 -0
  19. package/template/create-miden-app/template/.claude/skills/frontend-pitfalls/SKILL.md +189 -0
  20. package/template/create-miden-app/template/.claude/skills/frontend-source-guide/SKILL.md +163 -0
  21. package/template/create-miden-app/template/.claude/skills/miden-concepts/SKILL.md +108 -0
  22. package/template/create-miden-app/template/.claude/skills/react-sdk-patterns/SKILL.md +294 -0
  23. package/template/create-miden-app/template/.claude/skills/signer-integration/SKILL.md +158 -0
  24. package/template/create-miden-app/template/.claude/skills/vite-wasm-setup/SKILL.md +128 -0
  25. package/template/create-miden-app/template/.env.example +5 -0
  26. package/template/create-miden-app/template/CLAUDE.md +116 -0
  27. package/template/create-miden-app/template/README.md +61 -0
  28. package/template/create-miden-app/template/eslint.config.js +23 -0
  29. package/template/create-miden-app/template/index.html +13 -0
  30. package/template/create-miden-app/template/package.json +34 -0
  31. package/template/create-miden-app/template/public/vite.svg +1 -0
  32. package/template/create-miden-app/template/src/App.tsx +10 -0
  33. package/template/create-miden-app/template/src/assets/miden.svg +3 -0
  34. package/template/create-miden-app/template/src/assets/react.svg +1 -0
  35. package/template/{src/App.css → create-miden-app/template/src/components/AppContent.css} +9 -9
  36. package/template/create-miden-app/template/src/components/AppContent.tsx +50 -0
  37. package/template/create-miden-app/template/src/components/Counter.css +27 -0
  38. package/template/create-miden-app/template/src/components/Counter.tsx +45 -0
  39. package/template/create-miden-app/template/src/config.ts +21 -0
  40. package/template/create-miden-app/template/src/hooks/useIncrementCounter.ts +136 -0
  41. package/template/create-miden-app/template/src/index.css +75 -0
  42. package/template/create-miden-app/template/src/lib/miden.ts +9 -0
  43. package/template/create-miden-app/template/src/main.tsx +10 -0
  44. package/template/create-miden-app/template/src/providers.tsx +31 -0
  45. package/template/create-miden-app/template/src/vite-env.d.ts +1 -0
  46. package/template/create-miden-app/template/tsconfig.app.json +32 -0
  47. package/template/create-miden-app/template/tsconfig.json +7 -0
  48. package/template/create-miden-app/template/tsconfig.node.json +24 -0
  49. package/template/create-miden-app/template/vite.config.ts +17 -0
  50. package/template/create-miden-app/template/yarn.lock +1697 -0
  51. package/template/index.html +1 -1
  52. package/template/package.json +17 -8
  53. package/template/public/packages/counter_account.masp +0 -0
  54. package/template/public/packages/increment_note.masp +0 -0
  55. package/template/src/App.tsx +6 -59
  56. package/template/src/__tests__/fixtures/accounts.ts +57 -0
  57. package/template/src/__tests__/fixtures/index.ts +21 -0
  58. package/template/src/__tests__/fixtures/notes.ts +33 -0
  59. package/template/src/__tests__/mocks/miden-sdk-react.ts +244 -0
  60. package/template/src/__tests__/patterns/README.md +44 -0
  61. package/template/src/__tests__/patterns/mutation-hook.test.tsx +146 -0
  62. package/template/src/__tests__/patterns/provider-setup.test.tsx +75 -0
  63. package/template/src/__tests__/patterns/query-hook.test.tsx +143 -0
  64. package/template/src/components/AppContent.css +45 -0
  65. package/template/src/components/AppContent.tsx +50 -0
  66. package/template/src/components/Counter.css +27 -0
  67. package/template/src/components/Counter.tsx +45 -0
  68. package/template/src/components/__tests__/AppContent.test.tsx +86 -0
  69. package/template/src/components/__tests__/Counter.test.tsx +114 -0
  70. package/template/src/config.ts +21 -0
  71. package/template/src/hooks/useIncrementCounter.ts +136 -0
  72. package/template/src/index.css +7 -0
  73. package/template/src/lib/miden.ts +9 -0
  74. package/template/src/main.tsx +6 -6
  75. package/template/src/providers.tsx +31 -0
  76. package/template/src/vite-env.d.ts +1 -0
  77. package/template/tsconfig.app.json +8 -4
  78. package/template/tsconfig.node.json +1 -3
  79. package/template/vite.config.ts +5 -17
  80. package/template/vitest.config.ts +26 -0
  81. package/template/vitest.setup.ts +1 -0
  82. package/template/yarn.lock +1318 -799
  83. package/template/src/miden/lib/demo.ts +0 -105
package/cli.js CHANGED
@@ -39,12 +39,12 @@ async function main() {
39
39
  }
40
40
 
41
41
  console.log(`
42
- Done!
43
- Next steps:
44
- cd ${projectName}
45
- npm install
46
- npm run dev
47
- `);
42
+ Done! Next steps:
43
+
44
+ cd ${projectName}
45
+ yarn install
46
+ yarn dev
47
+ `);
48
48
  }
49
49
 
50
50
  main();
package/package.json CHANGED
@@ -1,16 +1,11 @@
1
1
  {
2
2
  "name": "create-miden-app",
3
- "version": "1.0.3",
3
+ "version": "1.0.6",
4
4
  "description": "A Miden Project Scaffold Template",
5
5
  "bin": {
6
6
  "create-miden-app": "cli.js"
7
7
  },
8
8
  "type": "module",
9
- "scripts": {
10
- "setup-v12": "./setup-v12.sh",
11
- "update-v12": "./update-v12.sh",
12
- "check-v12": "./check-v12-compatibility.sh"
13
- },
14
9
  "files": [
15
10
  "cli.js",
16
11
  "template/"
@@ -0,0 +1,45 @@
1
+ #!/bin/bash
2
+ # Validates that required .masp contract artifacts exist in public/packages/.
3
+ # Run before build or as a standalone check.
4
+
5
+ cd "$CLAUDE_PROJECT_DIR" 2>/dev/null || cd "$(dirname "$0")/../.." || exit 1
6
+
7
+ PACKAGES_DIR="public/packages"
8
+ ERRORS=0
9
+
10
+ if [ ! -d "$PACKAGES_DIR" ]; then
11
+ echo "ERROR: $PACKAGES_DIR directory does not exist"
12
+ exit 1
13
+ fi
14
+
15
+ # Check for .masp files
16
+ MASP_FILES=$(find "$PACKAGES_DIR" -name "*.masp" 2>/dev/null)
17
+
18
+ if [ -z "$MASP_FILES" ]; then
19
+ echo "ERROR: No .masp files found in $PACKAGES_DIR"
20
+ echo "Run 'cargo miden build' in the contract project and copy .masp files here."
21
+ exit 1
22
+ fi
23
+
24
+ echo "Contract artifacts in $PACKAGES_DIR:"
25
+ while IFS= read -r file; do
26
+ SIZE=$(wc -c < "$file" | tr -d ' ')
27
+ if [ "$SIZE" -eq 0 ]; then
28
+ echo " ERROR: $file is empty (0 bytes)"
29
+ ERRORS=$((ERRORS + 1))
30
+ elif [ "$SIZE" -lt 100 ]; then
31
+ echo " WARN: $file is suspiciously small ($SIZE bytes)"
32
+ else
33
+ echo " OK: $file ($SIZE bytes)"
34
+ fi
35
+ done <<< "$MASP_FILES"
36
+
37
+ if [ $ERRORS -gt 0 ]; then
38
+ echo ""
39
+ echo "$ERRORS artifact(s) have errors. Rebuild contracts with 'cargo miden build'."
40
+ exit 1
41
+ fi
42
+
43
+ echo ""
44
+ echo "All artifacts valid."
45
+ exit 0
@@ -0,0 +1,31 @@
1
+ #!/bin/bash
2
+ # Post-edit hook: runs tests affected by changes since last commit.
3
+ # Only triggers for .ts/.tsx files in src/. Uses vitest --changed for detection.
4
+
5
+ INPUT=$(cat)
6
+ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.filePath // empty')
7
+
8
+ # Only trigger for TypeScript/React files in src/
9
+ if [[ -z "$FILE_PATH" ]] || [[ "$FILE_PATH" != *.ts && "$FILE_PATH" != *.tsx ]]; then
10
+ exit 0
11
+ fi
12
+
13
+ if [[ "$FILE_PATH" != *"/src/"* ]]; then
14
+ exit 0
15
+ fi
16
+
17
+ cd "$CLAUDE_PROJECT_DIR" || exit 0
18
+
19
+ # Run tests affected by uncommitted changes (non-watch mode, no coverage)
20
+ TEST_OUTPUT=$(npx vitest --changed --run 2>&1)
21
+ EXIT_CODE=$?
22
+
23
+ if [ $EXIT_CODE -eq 0 ]; then
24
+ echo '{"hookSpecificOutput": {"additionalContext": "Affected tests passed"}}'
25
+ exit 0
26
+ else
27
+ # Show last 30 lines of test output for context
28
+ TRIMMED=$(echo "$TEST_OUTPUT" | tail -30)
29
+ echo "{\"hookSpecificOutput\": {\"additionalContext\": \"Affected tests FAILED. Fix failing tests before continuing.\n$TRIMMED\"}}"
30
+ exit 2
31
+ fi
@@ -0,0 +1,27 @@
1
+ #!/bin/bash
2
+ # Post-edit hook: runs TypeScript type checking when .ts/.tsx files in src/ are modified.
3
+ # Reads JSON input from stdin (Claude Code hook protocol).
4
+
5
+ INPUT=$(cat)
6
+ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.filePath // empty')
7
+
8
+ # Only trigger for TypeScript/React files in src/
9
+ if [[ -z "$FILE_PATH" ]] || [[ "$FILE_PATH" != *.ts && "$FILE_PATH" != *.tsx ]]; then
10
+ exit 0
11
+ fi
12
+
13
+ if [[ "$FILE_PATH" != *"/src/"* ]]; then
14
+ exit 0
15
+ fi
16
+
17
+ # Run TypeScript type checking from project root
18
+ cd "$CLAUDE_PROJECT_DIR" || exit 0
19
+
20
+ if npx tsc -b --noEmit 2>&1; then
21
+ echo '{"hookSpecificOutput": {"additionalContext": "TypeScript type check passed"}}'
22
+ exit 0
23
+ else
24
+ CHECK_OUTPUT=$(npx tsc -b --noEmit 2>&1 | tail -30)
25
+ echo "{\"hookSpecificOutput\": {\"additionalContext\": \"TypeScript type check FAILED. Fix type errors before continuing.\n$CHECK_OUTPUT\"}}"
26
+ exit 2
27
+ fi
@@ -0,0 +1,35 @@
1
+ {
2
+ "hooks": {
3
+ "PostToolUse": [
4
+ {
5
+ "matcher": "Edit|Write",
6
+ "hooks": [
7
+ {
8
+ "type": "command",
9
+ "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/typecheck.sh",
10
+ "timeout": 60,
11
+ "statusMessage": "Type checking modified files..."
12
+ },
13
+ {
14
+ "type": "command",
15
+ "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/run-affected-tests.sh",
16
+ "timeout": 120,
17
+ "statusMessage": "Running affected tests..."
18
+ }
19
+ ]
20
+ }
21
+ ],
22
+ "Stop": [
23
+ {
24
+ "hooks": [
25
+ {
26
+ "type": "command",
27
+ "command": "cd \"$CLAUDE_PROJECT_DIR\" && npx vitest --run && npx tsc -b --noEmit && npx vite build",
28
+ "timeout": 300,
29
+ "statusMessage": "Running full test suite + type check + build..."
30
+ }
31
+ ]
32
+ }
33
+ ]
34
+ }
35
+ }
@@ -0,0 +1,189 @@
1
+ ---
2
+ name: frontend-pitfalls
3
+ description: Critical pitfalls and safety rules for Miden frontend development. Covers WASM initialization, concurrent access crashes, COOP/COEP headers, BigInt handling, Bech32 network mismatches, IndexedDB state loss, auto-sync side effects, Vite configuration, and React rendering race conditions. Use when reviewing, debugging, or writing Miden frontend code.
4
+ ---
5
+
6
+ # Miden Frontend Pitfalls
7
+
8
+ ## FP1: WASM Initialization Race (CRITICAL)
9
+
10
+ Components that use Miden hooks before MidenProvider finishes WASM initialization will crash.
11
+
12
+ ```tsx
13
+ // WRONG — crashes if WASM not ready
14
+ function App() {
15
+ const { data } = useAccounts(); // throws before init
16
+ return <div>{data?.wallets.length}</div>;
17
+ }
18
+
19
+ // CORRECT — use loadingComponent or check isReady
20
+ <MidenProvider
21
+ config={{ rpcUrl: "devnet" }}
22
+ loadingComponent={<p>Loading WASM...</p>}
23
+ >
24
+ <App />
25
+ </MidenProvider>
26
+
27
+ // CORRECT — guard with isReady
28
+ function App() {
29
+ const { isReady } = useMiden();
30
+ if (!isReady) return <p>Loading...</p>;
31
+ return <WalletView />;
32
+ }
33
+ ```
34
+
35
+ ## FP2: Recursive WASM Access Crash (CRITICAL)
36
+
37
+ The WASM client is single-threaded. Concurrent calls crash with "recursive use of an object detected".
38
+
39
+ ```tsx
40
+ // WRONG — two operations running simultaneously
41
+ const handleClick = async () => {
42
+ sync(); // fires async
43
+ await send({ ... }); // runs concurrently — CRASH
44
+ };
45
+
46
+ // CORRECT — use runExclusive for sequential execution
47
+ const { runExclusive } = useMiden();
48
+ await runExclusive(async (client) => {
49
+ await client.syncState();
50
+ // now safe to do next operation
51
+ });
52
+ ```
53
+
54
+ Built-in hooks (useSend, useConsume, etc.) already use runExclusive internally. This pitfall applies when using `useMidenClient()` directly or mixing manual client calls with hook mutations.
55
+
56
+ ## FP3: COOP/COEP Headers Missing (CRITICAL)
57
+
58
+ WASM SharedArrayBuffer requires these headers. Without them, WASM init silently fails.
59
+
60
+ ```ts
61
+ // REQUIRED in vite.config.ts
62
+ server: {
63
+ headers: {
64
+ "Cross-Origin-Opener-Policy": "same-origin",
65
+ "Cross-Origin-Embedder-Policy": "require-corp",
66
+ },
67
+ },
68
+
69
+ // ALSO REQUIRED on production server (nginx, Vercel, Cloudflare)
70
+ // See vite-wasm-setup skill for deployment configs
71
+ ```
72
+
73
+ **Gotcha**: These headers break third-party iframes, external scripts without CORS, and OAuth popups. Use `credentialless` for COEP if cross-origin resources are needed.
74
+
75
+ **Note**: `midenVitePlugin()` from `@miden-sdk/vite-plugin` handles COOP/COEP automatically via its `crossOriginIsolation` option (defaults to `false` to avoid breaking OAuth popups). Enable it instead of setting headers manually.
76
+
77
+ ## FP4: BigInt Type Mismatch (HIGH)
78
+
79
+ All token amounts in the SDK are `bigint`. Passing `number` causes TypeScript errors or runtime failures.
80
+
81
+ ```tsx
82
+ // WRONG
83
+ await send({ from, to, assetId, amount: 1000 }); // number — fails
84
+ await createFaucet({ maxSupply: 1000000, ... }); // number — fails
85
+
86
+ // CORRECT
87
+ await send({ from, to, assetId, amount: 1000n }); // bigint literal
88
+ await createFaucet({ maxSupply: BigInt(1000000), ... }); // BigInt constructor
89
+
90
+ // CORRECT — use parseAssetAmount for user input
91
+ import { parseAssetAmount } from "@miden-sdk/react";
92
+ const amount = parseAssetAmount(inputValue, 8); // string → bigint
93
+ ```
94
+
95
+ **Gotcha**: `JSON.stringify` cannot serialize `bigint`. Use a custom replacer or convert to string first.
96
+
97
+ ## FP5: Bech32 Network Mismatch (HIGH)
98
+
99
+ Bech32-encoded account IDs include the network. A devnet address on testnet points to a different or nonexistent account.
100
+
101
+ ```tsx
102
+ // WRONG — hardcoding a bech32 address used across networks
103
+ const ADMIN = "miden1qy35..."; // this is network-specific!
104
+
105
+ // CORRECT — use hex format for cross-network compatibility
106
+ const ADMIN = "0x1234567890abcdef";
107
+
108
+ // CORRECT — derive bech32 per network
109
+ account.bech32id(); // returns correct bech32 for current network
110
+ ```
111
+
112
+ Both hex and bech32 formats work in all hooks. Prefer hex for constants, bech32 for display.
113
+
114
+ ## FP6: Auto-Sync Side Effects (MEDIUM)
115
+
116
+ Default `autoSyncInterval` is 15000ms (15 seconds). Each sync triggers re-renders in useAccounts, useAccount, useNotes, etc.
117
+
118
+ ```tsx
119
+ // PROBLEM — form resets every 15 seconds because parent re-renders
120
+ <MidenProvider config={{ rpcUrl: "devnet" }}>
121
+ <SendForm /> {/* re-renders on every sync */}
122
+ </MidenProvider>
123
+
124
+ // SOLUTION 1 — preferred: use stable keys and memoization
125
+ const MemoizedForm = React.memo(SendForm);
126
+
127
+ // SOLUTION 2 — disable auto-sync for manual control
128
+ <MidenProvider config={{ rpcUrl: "devnet", autoSyncInterval: 0 }}>
129
+ ```
130
+
131
+ ## FP7: IndexedDB State Loss (MEDIUM)
132
+
133
+ The client persists accounts, keys, and notes in IndexedDB. Browser "Clear site data", private browsing, or storage pressure can delete everything.
134
+
135
+ - Warn users that clearing browser data deletes their wallet
136
+ - Consider external signers (Para, Turnkey) for production — keys are server-side
137
+ - Implement account export/backup for local keystore users
138
+
139
+ ## FP8: Vite Configuration Requirements (MEDIUM)
140
+
141
+ The `@miden-sdk/vite-plugin` package handles all Miden-specific Vite config.
142
+ The minimal setup is:
143
+
144
+ ```ts
145
+ import { midenVitePlugin } from "@miden-sdk/vite-plugin";
146
+
147
+ export default defineConfig({
148
+ plugins: [react(), midenVitePlugin()],
149
+ });
150
+ ```
151
+
152
+ `midenVitePlugin()` handles: WASM loading, top-level await, WASM pre-bundling exclusion,
153
+ and optionally COOP/COEP headers (via the `crossOriginIsolation` option, defaults to `false`
154
+ to avoid breaking OAuth popups).
155
+
156
+ | Option | Default | Purpose |
157
+ |--------|---------|---------|
158
+ | `crossOriginIsolation` | `false` | Add COOP/COEP headers for SharedArrayBuffer |
159
+
160
+ Enable `crossOriginIsolation: true` only if your app doesn't use OAuth or cross-origin iframes.
161
+ For production COOP/COEP, set headers at the server level (see vite-wasm-setup skill).
162
+
163
+ ## FP9: React StrictMode Double-Init (LOW)
164
+
165
+ React 19 StrictMode double-invokes effects in development. MidenProvider handles this via `isInitializedRef`, but direct `WebClient.createClient()` calls will initialize twice.
166
+
167
+ ```tsx
168
+ // WRONG — manual client creation in useEffect
169
+ useEffect(() => {
170
+ const client = await WebClient.createClient(url); // called twice in dev
171
+ }, []);
172
+
173
+ // CORRECT — always use MidenProvider
174
+ <MidenProvider config={{ rpcUrl: "devnet" }}>
175
+ ```
176
+
177
+ ## Quick Reference
178
+
179
+ | # | Pitfall | Severity | One-Line Rule |
180
+ |---|---------|----------|---------------|
181
+ | FP1 | WASM init race | CRITICAL | Use loadingComponent or check isReady |
182
+ | FP2 | Recursive WASM | CRITICAL | Use runExclusive() for all direct client access |
183
+ | FP3 | COOP/COEP | CRITICAL | Add headers in vite.config.ts AND production server |
184
+ | FP4 | BigInt | HIGH | All amounts are bigint (1000n not 1000) |
185
+ | FP5 | Bech32 mismatch | HIGH | Match network in rpcUrl and addresses |
186
+ | FP6 | Auto-sync | MEDIUM | Set autoSyncInterval: 0 if UI stability matters |
187
+ | FP7 | IndexedDB loss | MEDIUM | Warn users; use external signers for production |
188
+ | FP8 | Vite config | MEDIUM | Use `midenVitePlugin()` — it handles all Miden Vite config |
189
+ | FP9 | StrictMode | LOW | Use MidenProvider, not manual client creation |
@@ -0,0 +1,163 @@
1
+ ---
2
+ name: frontend-source-guide
3
+ description: Guide for advanced Miden frontend development using source repo exploration. Covers AI development practices (Plan Mode, verification-driven development, context engineering, sub-agents) and maps the miden-client source repository for discovering advanced patterns. Use when building complex applications beyond basic hook usage, implementing custom signers, working with raw WebClient, or troubleshooting SDK internals.
4
+ ---
5
+
6
+ # Advanced Miden Frontend Development: Source-Guided Context Engineering
7
+
8
+ ## Development Approach
9
+
10
+ ### 1. Plan Mode First
11
+
12
+ For any non-trivial frontend application, start in Plan Mode before writing code.
13
+
14
+ - Explore React SDK source and examples to understand available patterns
15
+ - Design the component hierarchy, data flow, and which hooks to use
16
+ - Identify which built-in hooks cover your needs vs what requires raw WebClient
17
+ - Map out the user flow: account creation, token operations, note handling
18
+
19
+ Rule of thumb: if the task involves custom transactions, external signers, or patterns not covered by the basic skills, plan first.
20
+
21
+ ### 2. Verification-Driven Development
22
+
23
+ This is the single highest-leverage practice for AI-assisted frontend development.
24
+
25
+ **Type check loop**: After every file edit, run `npx tsc -b --noEmit`. The project's type check hook does this automatically. If types fail:
26
+ 1. Read the error message
27
+ 2. Search the React SDK source for the correct type signature or hook usage
28
+ 3. Adapt the working pattern to your use case
29
+ 4. Recheck
30
+
31
+ **Dev server loop**: Run `npm run dev` and check the browser. When something fails:
32
+ 1. Check the browser console for WASM errors, network errors, or React errors
33
+ 2. For WASM errors: check COOP/COEP headers and Vite config (see frontend-pitfalls skill)
34
+ 3. For unexpected behavior: compare your code against the example wallet in the React SDK
35
+
36
+ Never submit code that doesn't type-check. The verification loop is your quality guarantee.
37
+
38
+ ### 3. Context Engineering with Source Repos
39
+
40
+ The basic skills (react-sdk-patterns, frontend-pitfalls, vite-wasm-setup) cover standard patterns. For anything beyond those patterns, the miden-client source repository is the knowledge base.
41
+
42
+ **How to use source repos effectively**:
43
+ - Don't load entire repos into context. Use sub-agents to explore — they search, read relevant files, and summarize findings without filling the main conversation context.
44
+ - Read source files only when you need a specific answer (progressive disclosure)
45
+ - Look for working examples first, then adapt. The example wallet app is the most reliable reference.
46
+ - When you find a useful pattern in source, extract just what you need — the exact hook call, the exact type, the exact provider setup.
47
+
48
+ **Using sub-agents for exploration**:
49
+ - Launch an explore sub-agent with a specific question: "Find how useSwap handles the payback note type in the React SDK"
50
+ - The sub-agent searches, reads the relevant files, and returns a focused summary
51
+ - Your main context stays clean for implementation
52
+
53
+ ### 4. Iterative Frontend Development
54
+
55
+ Break complex applications into stages. Complete each before starting the next:
56
+
57
+ 1. **Design** (Plan Mode) — Component hierarchy, data flow, hook selection
58
+ 2. **Provider setup** — MidenProvider config, signer integration if needed
59
+ 3. **Query components** — Account display, balance rendering, note lists
60
+ 4. **Mutation components** — Send forms, mint buttons, consume flows
61
+ 5. **Transaction UX** — Stage progress, error handling, loading states
62
+ 6. **Polish** — Auto-sync tuning, memoization, edge cases
63
+
64
+ When stuck at any stage: search the React SDK source for a similar working pattern. Adapt it, don't guess.
65
+
66
+ ---
67
+
68
+ ## Miden Source Repository Map
69
+
70
+ Clone this repo alongside your project for reference. Claude will explore it when needed for advanced patterns.
71
+
72
+ ```bash
73
+ # Contains React SDK source, WebClient WASM bindings, and working examples
74
+ git clone --depth 1 https://github.com/0xMiden/miden-client.git ../miden-client
75
+ ```
76
+
77
+ ### `packages/react-sdk/` — React SDK Source
78
+
79
+ The primary reference for all frontend development.
80
+
81
+ - **`src/hooks/`** — All 18+ hook implementations. Each file is self-contained. Read these to understand exact parameters, error handling, and stage progression.
82
+ - **`src/context/MidenProvider.tsx`** — Client initialization, sync loop, signer detection, runExclusive lock. Read this to understand initialization order.
83
+ - **`src/context/SignerContext.ts`** — External signer interface. Read this when implementing custom signers.
84
+ - **`src/store/MidenStore.ts`** — Zustand store structure. Read this to understand cached state and what triggers re-renders.
85
+ - **`src/utils/`** — Utility implementations (amounts, notes, bech32, runExclusive, accountParsing).
86
+ - **`src/types/index.ts`** — All TypeScript interfaces. The single source of truth for option types, result types, and configuration.
87
+ - **`examples/wallet/`** — Complete working wallet app. The most reliable reference for how to set up MidenProvider, create accounts, display balances, claim notes, and send tokens.
88
+
89
+ **Explore when**: Writing any new component, understanding exact hook behavior, finding how a specific feature works, debugging unexpected behavior.
90
+
91
+ ### `crates/web-client/` — WASM Client Bindings
92
+
93
+ The Rust-to-WASM bridge that the React SDK wraps.
94
+
95
+ - Contains the `WebClient` struct and all methods available via `useMidenClient()`
96
+ - JavaScript bindings in `js/` directory
97
+
98
+ **Explore when**: A hook doesn't exist for your operation, understanding what WebClient methods are available, debugging WASM-level errors.
99
+
100
+ ### `crates/idxdb-store/` — IndexedDB Persistence
101
+
102
+ The browser storage layer for accounts, keys, notes, and transaction history.
103
+
104
+ **Explore when**: Debugging data persistence issues, understanding what's stored in IndexedDB, investigating storage isolation for external signers.
105
+
106
+ ---
107
+
108
+ ## What to Explore for Each Pattern
109
+
110
+ | Building This | Explore These Paths | What to Look For |
111
+ |---|---|---|
112
+ | Basic wallet UI | `examples/wallet/` | MidenProvider setup, useAccounts, useSend |
113
+ | Custom transaction | `src/hooks/useTransaction.ts` | Request factory pattern, client methods |
114
+ | External signer | `src/context/SignerContext.ts` | SignerContextValue interface, signCb |
115
+ | Note consumption flow | `src/hooks/useConsume.ts` | NoteId parsing, filter construction |
116
+ | Swap UI | `src/hooks/useSwap.ts` | Swap options, dual note types |
117
+ | Token display | `src/utils/amounts.ts` | formatAssetAmount, parseAssetAmount |
118
+ | Account ID formatting | `src/utils/accountBech32.ts` | toBech32AccountId |
119
+ | State management | `src/store/MidenStore.ts` | Zustand selectors, cached state |
120
+ | Direct WebClient usage | `src/context/MidenProvider.tsx` | useMidenClient(), runExclusive |
121
+ | Multi-step workflow | `src/hooks/useWaitForCommit.ts`, `useWaitForNotes.ts` | Polling, timeout patterns |
122
+
123
+ ---
124
+
125
+ ## Common Advanced Patterns
126
+
127
+ ### Custom Hooks Wrapping WebClient
128
+ For operations not covered by built-in hooks, create custom hooks that use useMidenClient() and runExclusive:
129
+ ```tsx
130
+ function useBlockHeader(blockNumber: number) {
131
+ const client = useMidenClient();
132
+ const { runExclusive } = useMiden();
133
+ const [data, setData] = useState(null);
134
+ useEffect(() => {
135
+ // Note: runExclusive() may be simplified in a future SDK version.
136
+ // Check SDK changelog when upgrading.
137
+ runExclusive(async () => {
138
+ const header = await client.getBlockHeaderByNumber(blockNumber);
139
+ setData(header);
140
+ });
141
+ }, [blockNumber]);
142
+ return data;
143
+ }
144
+ ```
145
+
146
+ ### Multi-Step Workflows
147
+ Compose hooks for complex flows (mint → wait for commit → sync → consume):
148
+ ```tsx
149
+ const { mutate: mint } = useMint();
150
+ const { mutate: waitForCommit } = useWaitForCommit();
151
+ const { mutate: waitForNotes } = useWaitForNotes();
152
+ const { mutate: consume } = useConsume();
153
+
154
+ const mintAndConsume = async () => {
155
+ const { transactionId } = await mint({ targetAccountId, faucetId, amount });
156
+ await waitForCommit({ transactionId });
157
+ await waitForNotes({ accountId: targetAccountId });
158
+ await consume({ accountId: targetAccountId, noteIds: [...] });
159
+ };
160
+ ```
161
+
162
+ ### Custom Signer Implementation
163
+ Implement the SignerContextValue interface, wrap MidenProvider in your provider. Reference `src/context/SignerContext.ts` for the exact interface contract. The `storeName` field must be unique per user to ensure IndexedDB isolation.
@@ -0,0 +1,108 @@
1
+ ---
2
+ name: miden-concepts
3
+ description: Miden architecture and core concepts from a developer perspective. Covers the actor model, accounts, notes, transactions, assets, privacy model, and standard patterns. Use when designing Miden applications or understanding how Miden differs from traditional blockchains.
4
+ ---
5
+
6
+ # Miden Architecture for Developers
7
+
8
+ ## What is Miden?
9
+
10
+ Miden is a zero-knowledge rollup that uses an **actor model** where each account is an independent smart contract. It settles on Ethereum via validity proofs through Agglayer.
11
+
12
+ Key properties:
13
+ - **Privacy by default** — accounts, notes, and transactions are private; the network stores only cryptographic commitments
14
+ - **Client-side execution** — transactions are executed and proven locally by the user's device
15
+ - **Programmable everything** — accounts hold code and storage; notes carry scripts and assets
16
+
17
+ ## Mental Model Shifts from Traditional Blockchains
18
+
19
+ | Traditional (Ethereum) | Miden |
20
+ |------------------------|-------|
21
+ | Transactions involve sender + receiver | Transactions involve **one account only** |
22
+ | Public state by default | **Private by default** |
23
+ | Validators execute transactions | **Client executes and proves** locally |
24
+ | Gas metering | No gas (computational bounds exist) |
25
+ | Synchronous contract calls | **Asynchronous** communication via notes |
26
+ | Accounts are balances + storage | Accounts are **full smart contracts** with code, storage, and vault |
27
+
28
+ ## Core Concepts
29
+
30
+ ### Accounts
31
+ Each account is an independent smart contract containing:
32
+ - **Code** — Immutable logic compiled from Rust components
33
+ - **Storage** — Up to 255 slots (Value or StorageMap)
34
+ - **Vault** — Holds fungible and non-fungible assets
35
+ - **Nonce** — Incremented with each state change
36
+ - **ID** — Unique identifier (prefix + suffix, 2 Felts)
37
+
38
+ Accounts are composed from **components** — reusable Rust modules annotated with `#[component]`.
39
+
40
+ ### Notes
41
+ Notes are **UTXO-like messages** for asynchronous inter-account communication. A note contains:
42
+ - **Script** — Logic that executes when the note is consumed
43
+ - **Inputs** — Data passed to the script (Vec<Felt>)
44
+ - **Assets** — Fungible/non-fungible tokens attached to the note
45
+ - **Metadata** — Sender, tag, note type (public/private)
46
+
47
+ Notes are created as **output notes** by one transaction and consumed as **input notes** by another.
48
+
49
+ ### Transactions
50
+ A transaction is a **single-account state transition** with 4 phases:
51
+ 1. Consume input notes (execute their scripts against the account)
52
+ 2. Execute transaction script (optional, for one-off logic)
53
+ 3. Update account state (storage, vault, nonce)
54
+ 4. Produce output notes (for other accounts to consume later)
55
+
56
+ **Important**: A two-party transfer (Alice sends Bob tokens) requires TWO transactions:
57
+ 1. Alice's transaction creates a P2ID note with tokens attached
58
+ 2. Bob's transaction consumes that note, receiving the tokens
59
+
60
+ ### Assets
61
+ - **Fungible**: `[amount, 0, faucet_suffix, faucet_prefix]` (1 Word)
62
+ - **Non-fungible**: Unique token tied to a faucet account
63
+ - Assets live in account **vaults** and move between accounts via notes
64
+ - Created by **faucet accounts** using `faucet::create_fungible_asset()` or `faucet::mint()`
65
+
66
+ ### Felt and Word
67
+ - **Felt**: Field element in the Goldilocks prime field (p = 2^64 - 2^32 + 1). The fundamental data unit.
68
+ - **Word**: Array of 4 Felts (32 bytes). Used for cryptographic hashes, storage keys, account IDs.
69
+
70
+ **WARNING**: Felt arithmetic is **modular**. Subtraction wraps around the prime. Always validate with `.as_u64()` before subtracting. See the miden-pitfalls skill for details.
71
+
72
+ ## Standard Note Patterns
73
+
74
+ | Pattern | Purpose | How It Works |
75
+ |---------|---------|-------------|
76
+ | **P2ID** | Send assets to a specific account | Note script checks consumer's ID matches target |
77
+ | **P2IDE** | P2ID with expiration | Adds block-height timelock; sender can reclaim after expiry |
78
+ | **SWAP** | Atomic asset exchange | Note offers asset A, requests asset B; consumer provides B |
79
+
80
+ ## Standard Components (miden-standards)
81
+
82
+ | Component | Purpose |
83
+ |-----------|---------|
84
+ | `BasicWallet` | Standard wallet: `receive_asset()`, `move_asset_to_note()` |
85
+ | `BasicFungibleFaucet` | Mint/burn fungible tokens |
86
+ | `NoAuth` | No authentication (for testing) |
87
+ | `AuthFalcon512Rpo` | Production signature authentication |
88
+
89
+ ## Development Model
90
+
91
+ ```
92
+ Developer writes Rust → Compiler produces MASM → VM executes and proves
93
+ ```
94
+
95
+ Three contract types:
96
+ - `#[component]` — Account logic and storage (can have multiple per account)
97
+ - `#[note]` — Note script (executes when consumed)
98
+ - `#[tx_script]` — One-off transaction logic
99
+
100
+ Contracts are tested locally with **MockChain** (no network needed) and deployed via **miden-client**.
101
+
102
+ ## Key Design Decisions for App Architects
103
+
104
+ 1. **One account per service** — Each bank, vault, or DEX pool is a separate account
105
+ 2. **Notes for communication** — Use deposit/withdraw/request notes instead of direct calls
106
+ 3. **Storage for state** — Use `Value` for flags, `StorageMap` for mappings
107
+ 4. **Privacy by default** — Choose `NoteType::Public` only when discoverability is needed
108
+ 5. **Components for reuse** — Standard wallet, auth, and faucet components compose into accounts