You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This issue captures a full educational audit of every example in this repository, conducted to determine what to keep, refocus, or remove in preparation for referencing examples from dfinity/developer-docs.
Every verdict is based on reading the actual source code, not just READMEs. The focus is educational and structural value only. Tooling migrations (dfx → icp-cli) are tracked separately.
The docs integration mapping at the bottom supersedes the aspirational mapping in developer-docs#44 and can be used to drive Phase 2 of that work (adding // #region markers).
Quick-reference verdict table
Example
Verdict
hosting/godot-html5-template
Keep
hosting/my_crypto_blog
Remove
hosting/oisy-signer-demo
Keep
hosting/photo-storage
Keep but refocus
hosting/react
Keep
hosting/static-website
Keep
hosting/unity-webgl-template
Keep
native-apps/unity_ii_deeplink
Keep but refocus (consolidate)
native-apps/unity_ii_applink
Remove (merge into deeplink)
native-apps/unity_ii_universallink
Remove (merge into deeplink)
svelte/svelte-motoko-starter
Keep but refocus
svelte/sveltekit-starter
Keep but refocus
wasm/counter
Keep
motoko/backend_only
Keep but refocus
motoko/basic_bitcoin
Keep
motoko/canister_factory
Keep
motoko/canister_logs
Keep
motoko/cert-var
Keep but refocus
motoko/classes
Keep
motoko/composite_query
Keep
motoko/daily_planner
Keep but refocus
motoko/encrypted-notes-dapp-vetkd
Remove
motoko/evm_block_explorer
Keep
motoko/filevault
Keep
motoko/flying_ninja
Keep
motoko/hello_cycles
Keep
motoko/hello_world
Keep
motoko/ic-pos
Keep but refocus
motoko/icp_transfer
Keep but refocus
motoko/icrc2-swap
Keep
motoko/llm_chatbot
Keep
motoko/low_wasm_memory
Keep
motoko/nft-creator
Remove
motoko/parallel_calls
Keep
motoko/pub-sub
Keep
motoko/query_stats
Keep
motoko/random_maze
Keep but refocus
motoko/send_http_get
Keep
motoko/send_http_post
Keep
motoko/superheroes
Keep
motoko/threshold-ecdsa
Keep
motoko/threshold-schnorr
Keep
motoko/token_transfer
Remove (consolidated into icrc_ledger)
motoko/token_transfer_from
Remove (consolidated into icrc_ledger)
motoko/tokenmania
Remove
motoko/vetkd
Keep but refocus
motoko/vetkeys
Remove
motoko/who_am_i
Keep
rust/backend_only
Keep
rust/backend_wasm64
Keep but refocus
rust/basic_bitcoin
Keep
rust/basic_dogecoin
Remove
rust/basic_ethereum
Keep
rust/basic_solana
Remove
rust/candid_type_generation
Keep but refocus
rust/canister-info
Keep
rust/canister-snapshot-download
Keep but refocus
rust/canister-snapshots
Keep
rust/canister_logs
Keep
rust/composite_query
Keep but refocus
rust/daily_planner
Keep
rust/encrypted-notes-dapp-vetkd
Remove
rust/evm_block_explorer
Keep but refocus
rust/exchange-rates
Keep
rust/face-recognition
Keep but refocus
rust/flying_ninja
Keep
rust/guards
Keep
rust/hello_world
Keep but refocus
rust/icp_transfer
Keep but refocus
rust/image-classification
Keep
rust/inter-canister-calls
Keep
rust/llm_chatbot
Keep
rust/low_wasm_memory
Keep
rust/parallel_calls
Keep
rust/performance_counters
Keep
rust/periodic_tasks
Keep
rust/photo_gallery
Keep but refocus
rust/qrcode
Keep
rust/query_stats
Keep
rust/receiving-icp
Keep
rust/send_http_get
Keep
rust/send_http_post
Keep
rust/simd
Keep
rust/stake_neuron_from_cli
Keep but refocus
rust/threshold-ecdsa
Keep
rust/threshold-schnorr
Keep
rust/token_transfer
Remove (consolidated into icrc_ledger)
rust/token_transfer_from
Remove (consolidated into icrc_ledger)
rust/tokenmania
Remove
rust/unit_testable_rust_canister
Keep
rust/vetkd
Keep
rust/vetkeys/basic_bls_signing
Keep
rust/vetkeys/basic_ibe
Keep
rust/vetkeys/basic_timelock_ibe
Keep but refocus
rust/vetkeys/encrypted_chat
Remove
rust/vetkeys/encrypted_notes_dapp_vetkd
Keep but refocus
rust/vetkeys/password_manager
Keep
rust/vetkeys/password_manager_with_metadata
Keep
rust/who_am_i
Keep
rust/x509
Keep
Counts: Remove 16 | Keep but refocus 23 | Keep 61
REMOVE (16)
Stub redirects with no local source code (5)
These directories contain only a README pointing somewhere else. They add navigation confusion and no educational value. Docs can link to the target repos directly.
motoko/encrypted-notes-dapp-vetkd — Points to dfinity/vetkeys. The real example lives at rust/vetkeys/encrypted_notes_dapp_vetkd. No source here.
motoko/vetkeys — Points to ../../rust/vetkeys/. No source here. Confusing because Motoko backends for vetkeys examples actually exist inside rust/vetkeys/*/motoko/ subdirectories.
rust/encrypted-notes-dapp-vetkd — Points to dfinity/vetkeys. Same as motoko stub above.
rust/basic_dogecoin — Points to dfinity/dogecoin-canister. No source here.
rust/basic_solana — Points to dfinity/sol-rpc-canister. No source here.
Two hosting examples that should consolidate into one (2)
native-apps/unity_ii_applink — The delegation chain architecture (the actual teaching content) is byte-for-byte identical to unity_ii_deeplink. The only difference is the return URL (HTTPS instead of a custom scheme) and one Android manifest intent filter change. This is a variant of deeplink, not a separate concept. Should be a section in a consolidated native-apps example.
native-apps/unity_ii_universallink — Same as above, for iOS. The unique content is a CFBundleURLTypes plist patch and an Apple App Site Association file. Again, a variant of deeplink worth documenting as a platform section rather than a top-level example.
Research prototype mislabeled as a teaching example (1)
rust/vetkeys/encrypted_chat — 1,500+ lines across Rust + Svelte + TypeScript. The README carries an explicit "Disclaimer: This is an unfinished prototype. DO NOT USE IN PRODUCTION." It has an active copy-paste bug in the resharing context function. It is not in the top-level vetkeys README. The vetKey API calls inside it (vetkd_derive_key, vetkd_public_key) are identical to basic_ibe — nothing new is shown at the protocol level. A developer opening this to learn vetKeys will be overwhelmed without gaining anything that basic_ibe doesn't already teach. Its presence in the examples repo as a sibling of the teaching examples sets wrong expectations.
Token examples consolidated into icrc_ledger (6)
motoko/token_transfer, rust/token_transfer — Thin wrappers around icrc1_transfer. The entire example is a single function. This granularity only made sense before a comprehensive icrc_ledger example existed. As regions inside icrc_ledger, the same snippet is available without a separate project.
motoko/token_transfer_from, rust/token_transfer_from — Same reasoning. icrc2_approve + icrc2_transfer_from become regions in icrc_ledger.
motoko/tokenmania, rust/tokenmania — A from-scratch ICRC-1/2 ledger implementation. Teaching developers to implement their own token ledger is the wrong lesson. They should deploy the official icrc1_ledger_canister and interact with it. The reference-implementation framing has no guide to back it up. Remove.
NFT example with no guide home (1)
motoko/nft-creator — Uses mo:icrc7-mo which depends on mo:base (already a signal it's not current). More importantly, NFTs as a concept are not where ICP's differentiation lies — the brand is moving away from crypto-era positioning toward sovereign infrastructure, tamperproof apps, and AI. ICRC-7 is a valid standard, but there is no guide in the docs it maps to, and "how to wire up an NFT library" teaches nothing about ICP specifically. No guide, no brand alignment, stale dependencies.
My_crypto_blog (1)
hosting/my_crypto_blog — Fetches posts from jsonplaceholder.typicode.com (a throwaway test API), calls the app a "crypto blog," and deploys it as a React asset canister. The icp.yaml is byte-for-byte identical to hosting/react. The additional complexity (fetch + loading state + error handling) adds noise rather than ICP-specific knowledge. The name and the centralized API call together create confusion, not clarity. hosting/react covers the same concept better.
KEEP, but refocus (23)
These have real educational value but something specific reduces their usefulness. The "what to fix" is actionable.
hosting/photo-storage
Teaches: Programmatic asset uploads via AssetManager.batch() from @icp-sdk/canisters/assets — including batch semantics, progress callbacks, and chunk handling. Unique concept not covered elsewhere. Problem: The hardcoded identity is acknowledged as a placeholder but left unresolved. An example that says "replace this before mainnet" teaches an incomplete pattern. Fix: Wire up Internet Identity for the upload authorization. Then this becomes the canonical "programmatic asset canister upload" reference.
native-apps/unity_ii_deeplink
Teaches: The delegation chain bridge between Internet Identity (browser) and a native mobile app: intermediate ECDSA key creation, chaining a second delegation from that key to the app's Ed25519 public key, and passing the DelegationChain back via a deep link. Non-trivial and correctly implemented. Problem: Three near-identical examples (deeplink, applink, universallink) obscure the core concept in platform boilerplate. A developer needs to read all three to understand what's different. Fix: Make unity_ii_deeplink the root example. Add sections for "Android App Links (HTTPS verified)" and "iOS Universal Links" as documented variants within the same example, not separate top-level directories. Remove the other two as standalone examples.
svelte/svelte-motoko-starter
Teaches: II authentication in a Svelte + Motoko app — AuthClient.create() → login() → getIdentity() → actor creation with that identity → whoami() call. Clean pattern, correct concept. Problem: Uses @dfinity/auth-client and @dfinity/agent (the deprecated ICP SDK). The teaching point is correct but the API surface is outdated. Fix: Update to @icp-sdk/auth and @icp-sdk/core/agent. The conceptual structure stays identical; only the imports change.
svelte/sveltekit-starter
Teaches: How to call a Motoko canister from SvelteKit using auto-generated Candid actor declarations — createActor(canisterId, { agent }), actor.greet(input). Clear pattern for any JS framework. Problem: Uses @dfinity/agent for the actor. Same SDK staleness as above. Fix: Update to @icp-sdk/core/agent and @icp-sdk/core/actor. The pattern is sound.
motoko/backend_only
Teaches: A minimal persistent actor with a mutable greeting variable, one update and one query function — state that survives upgrades. Problem: Both backend_only and hello_world are minimal backend examples. The distinction between them (stateful with persistence vs. stateless) is not surfaced in either name or description. Developers don't know which to start with. Fix: Rename to persistent_greeting or similar, or add a clear note that this is "hello world with mutable state" to differentiate it from the truly minimal hello_world. The persistent keyword and its upgrade-safety semantics should be the headline.
motoko/cert-var
Teaches: Certified variables — CertifiedData.set() and CertifiedData.getCertificate() — so query responses can be cryptographically verified by clients without an update call. Important and unique concept. Problem: A manual blobOfNat32 byte-encoding helper (15+ lines of bit twiddling) is the first thing you read. It drowns out the 3-line CertifiedData API usage. Old webpack frontend. Fix: Replace the manual encoding with Text.encodeUtf8("42") or similar so the CertifiedData API is front and center. Modernize the frontend.
motoko/daily_planner
Teaches: Data persistence with mo:map/Map + HTTPS outcalls with transform function in one realistic application. Problem: Mixes three distinct concepts (CRUD data management, HTTPS outcalls, JSON parsing) in one file. Good as an integration example but not citable as a reference for any single concept. Contains a dead URL (internetcomputer.org/docs/current/...). Fix: Fix the dead URL. Clearly position this as an integration example ("see send_http_get for HTTPS outcalls in isolation"). The code itself is fine.
motoko/ic-pos
Teaches: Multiple valuable patterns: timer-based ckBTC ledger polling (the most instructive piece), per-merchant data isolation, owner-only access control, and HTTPS outcalls for notifications. Problem: All four concepts are mixed in 213 lines of application code. The timer-based polling pattern is buried. One HTTPS outcall uses transform = null which is incorrect practice for replicated mode. Fix: Fix the missing transform function. Add comments that explicitly call out each of the four patterns by name so developers can navigate to the concept they need. Consider whether this should become the canonical "monitoring an ICRC ledger" example.
motoko/icp_transfer
Teaches: Transferring ICP using the legacy ICP ledger API — TransferArgs with AccountIdentifier, Tokens in e8s, Memo. Problem: Developers may not realize this uses a legacy API. The ICP ledger supports ICRC-1 now, and icrc_ledger is the modern equivalent. Without a clear note, a developer might choose this as their starting point when they should use icrc_ledger. Fix: Add a prominent README note: "This uses the legacy ICP ledger API (account-identifier based). For new code, prefer icrc_ledger (ICRC-1). Use this if you're integrating with exchanges or existing infrastructure that uses account identifiers."
motoko/random_maze
Teaches:Random.crypto() for async cryptographic entropy on ICP, await* random.natRange(0, n) for bounded integers, and AsyncRandom usage in general. Problem: The actual ICP-relevant concept (the AsyncRandom API) is buried inside a moderately complex maze generation algorithm with bit-masking for wall/visited state tracking. A developer searching for "how to use ICP randomness" may not see the signal through the maze logic. Fix: Add a prominent comment block early in the file: "The ICP-specific pattern is in lines X–Y: Random.crypto() creates an async random source backed by the management canister. Everything else is maze-generation algorithm." Or extract the randomness into a simpler companion example.
motoko/vetkd
Teaches: The management canister vetKD API directly — vetkd_public_key and vetkd_derive_key for both "symmetric_key" and "ibe_encryption" contexts. 74 lines, both use cases side by side. Problem: The naming confusion between vetkd, vetkeys, and the vetkeys examples is significant. Two empty stub directories (motoko/vetkeys, motoko/encrypted-notes-dapp-vetkd) point to rust/vetkeys/*/motoko/ backends, but this standalone motoko/vetkd is unrelated to those. A developer exploring vetKeys will hit three directories and not understand the landscape. Fix: Remove the two stubs (done per Remove section). Keep motoko/vetkd as the minimal Motoko vetKD reference. Add a clear README note: "This is the minimal backend API example. For complete applications using vetKeys, see rust/vetkeys/."
rust/backend_wasm64
Teaches: That ICP supports Wasm64, enabling canisters to address more than 4GB of memory. Problem: The Rust source is identical to backend_only. The teaching is entirely in the Cargo.toml target and build configuration, which is easy to miss. Fix: Add a comment in lib.rs and a clear README: "This is backend_only compiled to the wasm64-unknown-unknown target. The source code is intentionally identical — the only difference is in Cargo.toml. Wasm64 enables memory addressing beyond 4GB."
rust/candid_type_generation
Teaches: Using ic-cdk-bindgen in build.rs to auto-generate Rust types from a Candid .did file, eliminating manual type duplication. Problem: The example bundles the build script pattern (the unique concept) with NNS governance inter-canister calls (a large, complex secondary concern). The two are separable. Fix: The build script pattern is the unique educational value. Consider whether the NNS governance call is the right downstream to demonstrate it against, or whether a simpler canister interface would be clearer. At minimum, the README should make the build script pattern the headline.
rust/canister-snapshot-download
Teaches: A scenario where stable memory is corrupted (represented by the minimal raw stable memory read/write canister), and how to download a snapshot, modify it, and re-upload to fix the corruption. Problem: The canister code itself (lib.rs, 21 lines) is a trivial stable memory demo without context. The teaching is in the surrounding scripts and docs. A developer reading lib.rs learns almost nothing about snapshots. Fix: Add inline comments explaining what this canister is demonstrating and why the stable memory layout matters for the snapshot scenario. Consider merging with canister-snapshots into one coherent "canister lifecycle: snapshot and restore" example.
rust/composite_query
Teaches: The #[query(composite = true)] attribute for making inter-canister calls from a query context — reduces latency significantly for read-heavy multi-canister architectures. Problem: The example embeds a canister factory pattern (creating and installing partition canisters from Wasm bytes at runtime) alongside the composite query pattern. The two concepts are orthogonal, and the factory code adds complexity that distracts from the composite query point. Fix: Strip or move the canister factory logic. Keep only the partition canister pattern needed to demonstrate composite = true. The get vs get_update comparison is excellent and should be front and center.
rust/evm_block_explorer
Teaches (should be): Querying Ethereum block data via the EVM RPC canister, handling multi-provider consensus results (#Consistent(#Ok), #Consistent(#Err), #Inconsistent). Problem: The example also includes sign_message_with_ecdsa and sign_message_with_schnorr functions that have nothing to do with block exploration. The scope is incoherent — it's a block explorer and a key demo simultaneously. Fix: Remove or extract the signing functions. Keep only the block fetching and the three-way consensus result handling. The name should match the concept: this is about eth_get_block_by_number and multi-provider result handling.
rust/face-recognition
Teaches: Running ONNX neural network inference on ICP via ic_wasi_polyfill (WASI compatibility layer inside a canister), loading large model binaries in chunks via stable memory. Problem: The chunked model upload and WASI polyfill patterns are the ICP-specific teaching points, but they are buried under two ONNX model pipelines and the ML inference code. Developers building AI apps need to extract the infra patterns from the ML logic. Fix: Add a dedicated comment section (or README section) explicitly naming the ICP-specific patterns: "1. How chunked stable memory upload works (lines X–Y). 2. How ic_wasi_polyfill::init() provides WASI compatibility (line Z)."
rust/hello_world
Teaches: Persisting a greeting prefix in a StableBTreeMapCell via MemoryManager, exposing a set_greeting update and greet query. Problem: The name says "hello world" but the code teaches stable memory persistence with ic_stable_structures. backend_only is the actual hello world (4 lines, one query). A new developer opening hello_world expecting an entry point gets an intermediate stable-memory lesson. Fix: Rename to persistent_greeting or stable_memory_greeting. Make backend_only the primary entry point. Or explicitly add a README note: "This example teaches stable memory, not hello world. For the minimal starting point, see backend_only."
rust/icp_transfer
Teaches: Transferring ICP using the legacy ic_ledger_types crate — AccountIdentifier, Tokens, transfer(). Problem: Same issue as motoko/icp_transfer. The legacy API is correct for some use cases (exchange integrations, existing infrastructure) but should not be the first thing developers reach for. Fix: Add a prominent README note distinguishing legacy vs ICRC-1. Cross-link to icrc_ledger.
rust/photo_gallery
Teaches: Implementing the http_request query handler to serve binary content (images) from canister memory with cache headers via the HTTP gateway. Problem: Uses add_skip_certification_header, which opts out of asset certification entirely. This is the lazy path and is not safe for production. There is no explanation of the tradeoff. Fix: Add a comment explaining the skip-certification choice: "This example uses skip_certification for simplicity. In production, implement certified assets to cryptographically verify responses." Link to certified-variables guide or the asset canister pattern.
rust/stake_neuron_from_cli
Teaches: Programmatic NNS neuron staking from Rust using ic-agent — computing the staking subaccount hash (SHA-256 with domain separation), building a principal-signed agent, calling governance. Problem: This is a Rust CLI binary using ic-agent, not a canister. It is in a fundamentally different category from every other Rust example in the directory. Developers browsing canister examples will be confused when they find a CLI tool. Fix: Add a clear README header: "This is a Rust CLI program, not a canister. It demonstrates how to use ic-agent for programmatic interaction with an ICP canister from outside the IC." It is valuable in that category, just mislabeled.
rust/vetkeys/basic_timelock_ibe
Teaches: Canister-side decryption at a timed event — a canister holds its own transport key and uses a timer to trigger IBE key derivation and batch decryption of submitted ciphertexts. This is distinct from client-side decryption in basic_ibe. Problem: The auction application scaffolding (lot status machines, bid tracking, tie-breaking logic) is ~350 lines around a ~50-line crypto core. The key pattern — a canister acting as its own decrypter — is buried. The dummy vec![0; 32] transport key seed looks alarming without a comment explaining it is safe here (per-call ephemeral transport key). Fix: Add a comment explaining the dummy seed and why it's safe. Reduce the auction scaffolding or add explicit navigation comments pointing to the decrypt_ciphertexts() function as "the core teaching content."
rust/vetkeys/encrypted_notes_dapp_vetkd
Teaches: Per-resource symmetric key derivation using vetKeys: the note ID (not user principal) is the key derivation input, so the same key is accessible to any authorized user of that note. Also: caching non-extractable AES keys in IndexedDB — the only example in the set showing this pattern. Problem: The Motoko backend uses mo:base (deprecated) and preupgrade/postupgrade hooks (old pattern). This makes it a bad Motoko reference even though the concept is sound. Fix: Migrate Motoko backend to mo:core and persistent actor. The JavaScript pattern (IndexedDB caching of non-extractable keys) is genuinely unique and should be highlighted in the README.
KEEP (61)
These examples teach something distinct and do it well enough to reference from docs.
hosting/
godot-html5-template — Teaches: any pre-built static output (here: a Godot HTML5 export) can be deployed to ICP via an asset canister with a four-line config. Serves game developers who want confirmation their engine output works on ICP.
oisy-signer-demo — Teaches: the full ICRC signer standard (ICRC-29) flow — creating a Signer with PostMessageTransport, wrapping an HttpAgent in a SignerAgent for signed transactions, using anonymous agents for reads (no popup) and signer agents for writes (wallet popup). The useOisyWallet.js hook is well-commented production-quality code. Only example covering wallet integration standards.
hosting/react — Teaches: React/Vite app deployed as an ICP asset canister. The entire concept is in the icp.yaml. Correctly minimal.
hosting/static-website — Teaches: pure HTML/CSS/JS files deployed to ICP without any build tool. The no-Node-toolchain path is distinct from react and matters for developers not using a JS framework.
hosting/unity-webgl-template — Same concept as godot-html5-template but for Unity — the most widely used game engine. Distinct audience justifies a separate example despite structural similarity.
wasm/
wasm/counter — The best-written example in the entire collection from a pure educational standpoint. 106 lines of commented .wat demonstrating: IC System API imports (msg_reply, msg_reply_data_append, msg_arg_data_size, msg_arg_data_copy), the canister_query / canister_update export naming convention, manual Candid encoding with documented byte layout, and memory management. After reading this, a developer understands what Motoko and Rust CDKs are doing on their behalf. Irreplaceable as a System API reference.
motoko/
hello_world — Simplest possible entry point. Every platform needs a true hello world. Teach persistent actor + one query function. Keep as the "step 1."
who_am_i — 7 lines. Teaches public query (message) func and message.caller — the foundation of all access control on ICP. Essential for every developer.
canister_logs — Teaches: Debug.print behavior across update/query/timer contexts, intentional traps, and the difference between pre-trap logging and post-trap recovery. Each public function isolates one scenario.
classes — Teaches: actor classes as instantiatable canister blueprints, the with cycles syntax, and sharded state distribution across dynamically created canisters. Foundational for multi-canister architecture.
composite_query — Teaches: public composite query func for calling other canisters' query functions without consensus. The side-by-side getUpdate vs get (composite query) contrast makes the latency benefit concrete. Covers a distinct, non-obvious ICP capability.
canister_factory — Teaches: the four actor class lifecycle modes (#new, #install, #upgrade, #reinstall) and when to use actor class management vs. management canister calls directly. Includes before/after state comparisons for upgrade vs. reinstall. Uniquely comprehensive canister lifecycle reference.
evm_block_explorer — Teaches: EvmRpc.eth_getBlockByNumber and the three-way result type (#Consistent(#Ok), #Consistent(#Err), #Inconsistent) for multi-provider consensus. Good chain-fusion reference combining EVM RPC with ECDSA/Schnorr.
filevault — Teaches: per-principal data isolation using nested Map (principal → filename → blob chunks), chunked blob upload/retrieve. The principal-scoped pattern is fundamental to ICP security and is not as clearly shown in other examples.
flying_ninja — Teaches: in-memory sorted leaderboard, bounded array with insert-sort, and Random.blob() for client seeds. Concrete and relatable.
hello_cycles — Teaches: Cycles.balance(), Cycles.available() / Cycles.accept() for capping incoming cycles, and with cycles = amount + Cycles.refunded() for forwarding. The canonical cycles mechanics reference — no other example explains acceptance and forwarding this clearly.
icrc2-swap — The best security-focused example in the collection. Teaches: the deposit-swap-withdraw pattern, why the swap itself must be await-free for atomicity, and why withdrawal must debit-before-transfer (not the reverse) to prevent reentrancy. The inline comments explaining these design decisions are exceptional and rare in example code.
llm_chatbot — Teaches: both LLM.prompt() (single-turn) and LLM.chat() (multi-turn with message history) from mo:llm. 16 lines. On-chain AI is a differentiating ICP capability.
low_wasm_memory — Teaches: system func lowmemory() hook for proactive memory pressure handling before an OOM trap. No other example covers this operational resilience pattern.
parallel_calls — Teaches the critical ICP async performance pattern: fire all calls first, collect futures, then await them all (not await in a loop). The sequential vs. parallel contrast makes the difference concrete. The comment about calls failing under high load is an important practical note.
pub-sub — Teaches: passing and storing shared func references as inter-canister callbacks — idiomatic Motoko that enables pub-sub patterns without polling. The callback-as-field pattern is non-obvious and not demonstrated elsewhere.
send_http_get — The canonical HTTPS GET outcall reference. Teaches: transform function pattern, max_response_bytes with cost explanation, is_replicated = ?true for consensus, and cycle attachment. Inline comments are outstanding. #region markers make it doc-ready.
send_http_post — Companion to send_http_get. Adds: request body encoding, Content-Type header, is_replicated = ?false for non-replicated mode with idempotency key explanation. The GET/POST split is justified because the replicated/non-replicated semantics differ.
superheroes — The canonical CRUD reference. Create/read/update/delete on a Map with auto-incrementing IDs. Query vs. update distinction. Clean, 39 lines.
threshold-ecdsa — Canonical threshold ECDSA reference. Teaches: ecdsa_public_key and sign_with_ecdsa management canister calls, the three key ID environments (local/test/production), and SHA-256 pre-hashing. Essential for any chain-key signing use case.
threshold-schnorr — Canonical threshold Schnorr reference. Teaches both BIP340 (secp256k1, Bitcoin Taproot) and Ed25519 variants. BIP-341 taproot tweak is correctly isolated.
basic_bitcoin — Definitive Bitcoin integration reference. Teaches: P2PKH / P2WPKH / P2TR address derivation, UTXO management, fee estimation via percentiles, iterative transaction construction for P2TR Taproot. The Bitcoin-specific complexity is inherent to the domain, not bad code. Correctly labeled advanced.
rust/
backend_only — Correct hello world for Rust. Four lines, one query. The entry point.
basic_bitcoin — Same assessment as motoko: definitive Bitcoin wallet reference, comprehensive, appropriately advanced.
basic_ethereum — Teaches: ECDSA key derivation per principal, Ethereum address computation from secp256k1 public key, EIP-1559 transaction construction and signing via alloy, single-provider vs. multi-provider broadcast. Complete Ethereum wallet pattern.
canister-info — Teaches: canister_info management canister API for retrieving canister change history, controller hierarchies, and deployment chain traversal. Unique observability patterns not covered elsewhere.
canister-snapshots — Teaches: the value of snapshots via a creative approach — the canister has a deliberate, commented-and-flagged bug in remove_spam. After taking a snapshot, deploying the buggy upgrade, and observing the broken state, restoring the snapshot demonstrates the concept clearly. Memorable because of the intentional bug.
canister_logs — Teaches: ic_cdk::print, println!, trap in update/query/timer contexts. Covers all log production paths.
daily_planner — Good multi-concept integration example combining StableBTreeMap with custom Storable (Candid-serialized), HTTPS outcalls with transform, and CRUD. Realistic application that shows how the pieces connect.
exchange-rates — Teaches: calling the IC Exchange Rate Canister with Call::bounded_wait, attaching cycles, and decoding a typed response. Clean and focused.
flying_ninja — Same as Motoko: concrete game leaderboard with sorted in-memory state and raw_rand() usage.
guards — Essential security example. Teaches: RAII-based reentrancy prevention via Drop-based guard, and the critical nuance that the guard is only effective across await points (not within a synchronous message). The comment explaining TrueAsyncCall vs FalseAsyncCall (poll-to-completion vs yield) is one of the best educational comments in the entire library.
image-classification — Simpler ONNX entry point than face-recognition. Teaches: loading an ONNX model at init/post_upgrade, ic_wasi_polyfill::init() for WASI compatibility. Good first example for on-canister ML.
inter-canister-calls — Outstanding quality. Teaches: Call::unbounded_wait vs bounded_wait, with_arg, typed decoding, is_clean_reject() / is_immediately_retryable() error handling, retry-with-deadline pattern (stubborn_set), and cycle attachment. Each function in the caller canister teaches one distinct aspect. The comments about messaging model nuances are developer-essential material.
llm_chatbot — 20 lines, ic_llm crate, both prompt (single-turn) and chat (multi-turn). The simplest possible LLM entry point.
low_wasm_memory — Teaches #[on_low_wasm_memory] hook. Fix the stale "Bitcoin canister" comment but keep otherwise.
parallel_calls — future::join_all for concurrent inter-canister calls. The practical failure note under high load is important.
performance_counters — Teaches: instruction_counter() and call_context_instruction_counter() across await boundaries and in composite queries. Side-by-side comparison of counter behavior is unique.
periodic_tasks — Teaches: set_timer_interval (recommended) vs #[heartbeat] (legacy) with identical logic so the tradeoffs are directly comparable. The heartbeat limitations note is correct and useful.
qrcode — Teaches: CPU-intensive computation (QR code generation + PNG rendering + logo overlay) in a canister is viable. Both update and query endpoints. performance_counter(0) logging is a bonus.
query_stats — Unique monitoring pattern: query stats from canister_status.
receiving-icp — Teaches: computing a canister's AccountIdentifier and subaccounts, querying ICP balance. Practical complement to icp_transfer.
send_http_get and send_http_post — Among the best-written examples in the collection. Both referenced under Motoko assessment — same high marks apply.
simd — Teaches: Wasm SIMD128 in a Rust canister — naive, packed, auto-vectorized, and explicit SIMD implementations side by side with instruction_counter() benchmarking. Essential for ML/compute-intensive developers.
threshold-ecdsa — Canonical minimal threshold ECDSA reference for Rust. Key ID enum with three environment variants is the correct pattern.
threshold-schnorr — Canonical Schnorr reference for Rust. BIP341 Tapscript correctly isolated in wasm_only.rs. Includes integration tests.
unit_testable_rust_canister — The only example teaching DI-based unit testing for canisters: trait-based mocks, Arc<dyn Trait>, #[tokio::test] for async testing. Every serious Rust canister developer needs this pattern.
vetkd — Minimal vetKeys backend reference: vetkd_public_key and vetkd_derive_key for both symmetric key and IBE contexts. 87 lines, two use cases side by side.
who_am_i — Canonical msg_caller() reference. 10 lines.
x509 — Unique, sophisticated PKI example. Teaches: using threshold ECDSA and Schnorr keys as a Certificate Authority, CSR parsing and signature verification, root + leaf X.509 certificate issuance. Represents a genuinely novel ICP capability. For advanced developers building PKI infrastructure.
basic_ibe — The canonical, teachable IBE reference. Teaches the full round-trip: vetkd_public_key → IbeCiphertext.encrypt(publicKey, IbeIdentity.fromPrincipal(receiver)) → vetkd_derive_key(transport_key) → EncryptedVetKey.decryptAndVerify() → IbeCiphertext.decrypt(). The code in main.ts maps one-to-one onto the protocol steps. Every other IBE-using example should link back to this.
password_manager — Teaches: using the EncryptedMaps abstraction from the ic-vetkeys crate as a drop-in encrypted key-value store with access control. The contrast between the thin wrapper here and the raw API in encrypted_notes_dapp_vetkd is the key educational progression.
password_manager_with_metadata — Teaches one specific, real-world pattern: atomically updating an encrypted value (EncryptedMaps) and its unencrypted metadata (StableBTreeMap) in a single update call. The diff vs. password_manager is the entire lesson. Narrow and correct.
Structural observations
The "hello world" problem in Rust:backend_only (4 lines, correct entry point) and hello_world (stable memory with MemoryManager, an intermediate topic) have inverted roles. hello_world should be renamed.
vetKeys example architecture: The 6 examples (after removing encrypted_chat) form a clean three-layer progression that is worth making explicit:
Legacy vs. ICRC-1 ICP transfers:icp_transfer (both Motoko and Rust) covers the legacy ICP ledger API; icrc_ledger (to create) covers the ICRC-1 standard. Both are valid but serve different audiences — icp_transfer for exchange/infrastructure integrations, icrc_ledger for new code. They need clear cross-references.
daily_planner in both languages is an integration example that deliberately combines multiple concepts. It serves a different purpose from the focused single-concept examples. Both should be kept and positioned as "see how the pieces fit together."
The evm_block_explorer scope problem appears in both Motoko and Rust: a block explorer that also contains unrelated signing functions. Both need the same fix: remove or extract the signing.
This section drives Phase 2 of developer-docs#44: adding // #region markers to examples so the docs pipeline can extract snippets.
Format: Guide → canonical example(s) → suggested region names.
Region names are placeholders — refine during implementation. "Both" means Motoko + Rust versions exist or will be created.
Out of scope for the snippet pipeline (CLI commands, config, Candid spec, tooling guides): canister lifecycle CLI, icp.yaml config, custom domains, reproducible builds, Rosetta API, developer tools.
"DeFi" is banned as a section heading — it is a crypto-era category label, not a technical description. Use precise terms: ICRC-1, ICRC-2, token ledger, payments.
Guide
Example
Regions
ICRC ledger (deploy + interact)
New icrc_ledger (both) — replaces tokenmania, token_transfer, token_transfer_from
Note: ckbtc_deposit (deposit/withdrawal flow) is a gap — ic-pos shows polling patterns but not the deposit flow in isolation. Create or extract from ic-pos.
Issue #44 defines the snippet pipeline: region markers in examples → remark plugin → CodeExample component in docs. That pipeline is the right approach and Phase 1 implementation is underway.
This assessment is the prerequisite for Phase 2 (adding region markers). The guide→example mapping above supersedes the aspirational mapping in issue #44. Specifically:
tokenmania, token_transfer, and token_transfer_from (all listed in update dfx version so example runs without error #44) are replaced by a single icrc_ledger example with regions. The section is also renamed from "DeFi / tokens" to "Token transfers and payments"
evm_block_explorer needs scope fix before region markers are added
inter-canister-calls, periodic_tasks, cert-var all have Motoko gaps that must be filled before they can serve as dual-language doc examples
Several examples update dfx version so example runs without error #44 planned as "to create" (safe_calls, rate_limiter, safe_upgrades, tested_canister, ckbtc_deposit, sns_governed) are still gaps — docs for those guides should remain inline until examples exist
Recommended sequence:
Restructure the examples repo per this assessment (drop, consolidate, refocus)
This issue captures a full educational audit of every example in this repository, conducted to determine what to keep, refocus, or remove in preparation for referencing examples from dfinity/developer-docs.
Every verdict is based on reading the actual source code, not just READMEs. The focus is educational and structural value only. Tooling migrations (dfx → icp-cli) are tracked separately.
The docs integration mapping at the bottom supersedes the aspirational mapping in developer-docs#44 and can be used to drive Phase 2 of that work (adding
// #regionmarkers).Quick-reference verdict table
hosting/godot-html5-templatehosting/my_crypto_bloghosting/oisy-signer-demohosting/photo-storagehosting/reacthosting/static-websitehosting/unity-webgl-templatenative-apps/unity_ii_deeplinknative-apps/unity_ii_applinknative-apps/unity_ii_universallinksvelte/svelte-motoko-startersvelte/sveltekit-starterwasm/countermotoko/backend_onlymotoko/basic_bitcoinmotoko/canister_factorymotoko/canister_logsmotoko/cert-varmotoko/classesmotoko/composite_querymotoko/daily_plannermotoko/encrypted-notes-dapp-vetkdmotoko/evm_block_explorermotoko/filevaultmotoko/flying_ninjamotoko/hello_cyclesmotoko/hello_worldmotoko/ic-posmotoko/icp_transfermotoko/icrc2-swapmotoko/llm_chatbotmotoko/low_wasm_memorymotoko/nft-creatormotoko/parallel_callsmotoko/pub-submotoko/query_statsmotoko/random_mazemotoko/send_http_getmotoko/send_http_postmotoko/superheroesmotoko/threshold-ecdsamotoko/threshold-schnorrmotoko/token_transfericrc_ledger)motoko/token_transfer_fromicrc_ledger)motoko/tokenmaniamotoko/vetkdmotoko/vetkeysmotoko/who_am_irust/backend_onlyrust/backend_wasm64rust/basic_bitcoinrust/basic_dogecoinrust/basic_ethereumrust/basic_solanarust/candid_type_generationrust/canister-inforust/canister-snapshot-downloadrust/canister-snapshotsrust/canister_logsrust/composite_queryrust/daily_plannerrust/encrypted-notes-dapp-vetkdrust/evm_block_explorerrust/exchange-ratesrust/face-recognitionrust/flying_ninjarust/guardsrust/hello_worldrust/icp_transferrust/image-classificationrust/inter-canister-callsrust/llm_chatbotrust/low_wasm_memoryrust/parallel_callsrust/performance_countersrust/periodic_tasksrust/photo_galleryrust/qrcoderust/query_statsrust/receiving-icprust/send_http_getrust/send_http_postrust/simdrust/stake_neuron_from_clirust/threshold-ecdsarust/threshold-schnorrrust/token_transfericrc_ledger)rust/token_transfer_fromicrc_ledger)rust/tokenmaniarust/unit_testable_rust_canisterrust/vetkdrust/vetkeys/basic_bls_signingrust/vetkeys/basic_iberust/vetkeys/basic_timelock_iberust/vetkeys/encrypted_chatrust/vetkeys/encrypted_notes_dapp_vetkdrust/vetkeys/password_managerrust/vetkeys/password_manager_with_metadatarust/who_am_irust/x509Counts: Remove 16 | Keep but refocus 23 | Keep 61
REMOVE (16)
Stub redirects with no local source code (5)
These directories contain only a README pointing somewhere else. They add navigation confusion and no educational value. Docs can link to the target repos directly.
motoko/encrypted-notes-dapp-vetkd— Points todfinity/vetkeys. The real example lives atrust/vetkeys/encrypted_notes_dapp_vetkd. No source here.motoko/vetkeys— Points to../../rust/vetkeys/. No source here. Confusing because Motoko backends for vetkeys examples actually exist insiderust/vetkeys/*/motoko/subdirectories.rust/encrypted-notes-dapp-vetkd— Points todfinity/vetkeys. Same as motoko stub above.rust/basic_dogecoin— Points todfinity/dogecoin-canister. No source here.rust/basic_solana— Points todfinity/sol-rpc-canister. No source here.Two hosting examples that should consolidate into one (2)
native-apps/unity_ii_applink— The delegation chain architecture (the actual teaching content) is byte-for-byte identical tounity_ii_deeplink. The only difference is the return URL (HTTPS instead of a custom scheme) and one Android manifest intent filter change. This is a variant ofdeeplink, not a separate concept. Should be a section in a consolidated native-apps example.native-apps/unity_ii_universallink— Same as above, for iOS. The unique content is aCFBundleURLTypesplist patch and an Apple App Site Association file. Again, a variant ofdeeplinkworth documenting as a platform section rather than a top-level example.Research prototype mislabeled as a teaching example (1)
rust/vetkeys/encrypted_chat— 1,500+ lines across Rust + Svelte + TypeScript. The README carries an explicit "Disclaimer: This is an unfinished prototype. DO NOT USE IN PRODUCTION." It has an active copy-paste bug in the resharing context function. It is not in the top-level vetkeys README. The vetKey API calls inside it (vetkd_derive_key,vetkd_public_key) are identical tobasic_ibe— nothing new is shown at the protocol level. A developer opening this to learn vetKeys will be overwhelmed without gaining anything thatbasic_ibedoesn't already teach. Its presence in the examples repo as a sibling of the teaching examples sets wrong expectations.Token examples consolidated into
icrc_ledger(6)motoko/token_transfer,rust/token_transfer— Thin wrappers aroundicrc1_transfer. The entire example is a single function. This granularity only made sense before a comprehensiveicrc_ledgerexample existed. As regions insideicrc_ledger, the same snippet is available without a separate project.motoko/token_transfer_from,rust/token_transfer_from— Same reasoning.icrc2_approve+icrc2_transfer_frombecome regions inicrc_ledger.motoko/tokenmania,rust/tokenmania— A from-scratch ICRC-1/2 ledger implementation. Teaching developers to implement their own token ledger is the wrong lesson. They should deploy the officialicrc1_ledger_canisterand interact with it. The reference-implementation framing has no guide to back it up. Remove.NFT example with no guide home (1)
motoko/nft-creator— Usesmo:icrc7-mowhich depends onmo:base(already a signal it's not current). More importantly, NFTs as a concept are not where ICP's differentiation lies — the brand is moving away from crypto-era positioning toward sovereign infrastructure, tamperproof apps, and AI. ICRC-7 is a valid standard, but there is no guide in the docs it maps to, and "how to wire up an NFT library" teaches nothing about ICP specifically. No guide, no brand alignment, stale dependencies.My_crypto_blog (1)
hosting/my_crypto_blog— Fetches posts fromjsonplaceholder.typicode.com(a throwaway test API), calls the app a "crypto blog," and deploys it as a React asset canister. Theicp.yamlis byte-for-byte identical tohosting/react. The additional complexity (fetch + loading state + error handling) adds noise rather than ICP-specific knowledge. The name and the centralized API call together create confusion, not clarity.hosting/reactcovers the same concept better.KEEP, but refocus (23)
These have real educational value but something specific reduces their usefulness. The "what to fix" is actionable.
hosting/photo-storageTeaches: Programmatic asset uploads via
AssetManager.batch()from@icp-sdk/canisters/assets— including batch semantics, progress callbacks, and chunk handling. Unique concept not covered elsewhere.Problem: The hardcoded identity is acknowledged as a placeholder but left unresolved. An example that says "replace this before mainnet" teaches an incomplete pattern.
Fix: Wire up Internet Identity for the upload authorization. Then this becomes the canonical "programmatic asset canister upload" reference.
native-apps/unity_ii_deeplinkTeaches: The delegation chain bridge between Internet Identity (browser) and a native mobile app: intermediate ECDSA key creation, chaining a second delegation from that key to the app's Ed25519 public key, and passing the
DelegationChainback via a deep link. Non-trivial and correctly implemented.Problem: Three near-identical examples (
deeplink,applink,universallink) obscure the core concept in platform boilerplate. A developer needs to read all three to understand what's different.Fix: Make
unity_ii_deeplinkthe root example. Add sections for "Android App Links (HTTPS verified)" and "iOS Universal Links" as documented variants within the same example, not separate top-level directories. Remove the other two as standalone examples.svelte/svelte-motoko-starterTeaches: II authentication in a Svelte + Motoko app —
AuthClient.create()→login()→getIdentity()→ actor creation with that identity →whoami()call. Clean pattern, correct concept.Problem: Uses
@dfinity/auth-clientand@dfinity/agent(the deprecated ICP SDK). The teaching point is correct but the API surface is outdated.Fix: Update to
@icp-sdk/authand@icp-sdk/core/agent. The conceptual structure stays identical; only the imports change.svelte/sveltekit-starterTeaches: How to call a Motoko canister from SvelteKit using auto-generated Candid actor declarations —
createActor(canisterId, { agent }),actor.greet(input). Clear pattern for any JS framework.Problem: Uses
@dfinity/agentfor the actor. Same SDK staleness as above.Fix: Update to
@icp-sdk/core/agentand@icp-sdk/core/actor. The pattern is sound.motoko/backend_onlyTeaches: A minimal
persistent actorwith a mutablegreetingvariable, one update and one query function — state that survives upgrades.Problem: Both
backend_onlyandhello_worldare minimal backend examples. The distinction between them (stateful with persistence vs. stateless) is not surfaced in either name or description. Developers don't know which to start with.Fix: Rename to
persistent_greetingor similar, or add a clear note that this is "hello world with mutable state" to differentiate it from the truly minimalhello_world. Thepersistentkeyword and its upgrade-safety semantics should be the headline.motoko/cert-varTeaches: Certified variables —
CertifiedData.set()andCertifiedData.getCertificate()— so query responses can be cryptographically verified by clients without an update call. Important and unique concept.Problem: A manual
blobOfNat32byte-encoding helper (15+ lines of bit twiddling) is the first thing you read. It drowns out the 3-line CertifiedData API usage. Old webpack frontend.Fix: Replace the manual encoding with
Text.encodeUtf8("42")or similar so the CertifiedData API is front and center. Modernize the frontend.motoko/daily_plannerTeaches: Data persistence with
mo:map/Map+ HTTPS outcalls with transform function in one realistic application.Problem: Mixes three distinct concepts (CRUD data management, HTTPS outcalls, JSON parsing) in one file. Good as an integration example but not citable as a reference for any single concept. Contains a dead URL (
internetcomputer.org/docs/current/...).Fix: Fix the dead URL. Clearly position this as an integration example ("see
send_http_getfor HTTPS outcalls in isolation"). The code itself is fine.motoko/ic-posTeaches: Multiple valuable patterns: timer-based ckBTC ledger polling (the most instructive piece), per-merchant data isolation, owner-only access control, and HTTPS outcalls for notifications.
Problem: All four concepts are mixed in 213 lines of application code. The timer-based polling pattern is buried. One HTTPS outcall uses
transform = nullwhich is incorrect practice for replicated mode.Fix: Fix the missing
transformfunction. Add comments that explicitly call out each of the four patterns by name so developers can navigate to the concept they need. Consider whether this should become the canonical "monitoring an ICRC ledger" example.motoko/icp_transferTeaches: Transferring ICP using the legacy ICP ledger API —
TransferArgswithAccountIdentifier,Tokensin e8s,Memo.Problem: Developers may not realize this uses a legacy API. The ICP ledger supports ICRC-1 now, and
icrc_ledgeris the modern equivalent. Without a clear note, a developer might choose this as their starting point when they should useicrc_ledger.Fix: Add a prominent README note: "This uses the legacy ICP ledger API (account-identifier based). For new code, prefer
icrc_ledger(ICRC-1). Use this if you're integrating with exchanges or existing infrastructure that uses account identifiers."motoko/random_mazeTeaches:
Random.crypto()for async cryptographic entropy on ICP,await* random.natRange(0, n)for bounded integers, andAsyncRandomusage in general.Problem: The actual ICP-relevant concept (the
AsyncRandomAPI) is buried inside a moderately complex maze generation algorithm with bit-masking for wall/visited state tracking. A developer searching for "how to use ICP randomness" may not see the signal through the maze logic.Fix: Add a prominent comment block early in the file: "The ICP-specific pattern is in lines X–Y:
Random.crypto()creates an async random source backed by the management canister. Everything else is maze-generation algorithm." Or extract the randomness into a simpler companion example.motoko/vetkdTeaches: The management canister vetKD API directly —
vetkd_public_keyandvetkd_derive_keyfor both "symmetric_key" and "ibe_encryption" contexts. 74 lines, both use cases side by side.Problem: The naming confusion between
vetkd,vetkeys, and the vetkeys examples is significant. Two empty stub directories (motoko/vetkeys,motoko/encrypted-notes-dapp-vetkd) point torust/vetkeys/*/motoko/backends, but this standalonemotoko/vetkdis unrelated to those. A developer exploring vetKeys will hit three directories and not understand the landscape.Fix: Remove the two stubs (done per Remove section). Keep
motoko/vetkdas the minimal Motoko vetKD reference. Add a clear README note: "This is the minimal backend API example. For complete applications using vetKeys, seerust/vetkeys/."rust/backend_wasm64Teaches: That ICP supports Wasm64, enabling canisters to address more than 4GB of memory.
Problem: The Rust source is identical to
backend_only. The teaching is entirely in theCargo.tomltarget and build configuration, which is easy to miss.Fix: Add a comment in
lib.rsand a clear README: "This isbackend_onlycompiled to thewasm64-unknown-unknowntarget. The source code is intentionally identical — the only difference is inCargo.toml. Wasm64 enables memory addressing beyond 4GB."rust/candid_type_generationTeaches: Using
ic-cdk-bindgeninbuild.rsto auto-generate Rust types from a Candid.didfile, eliminating manual type duplication.Problem: The example bundles the build script pattern (the unique concept) with NNS governance inter-canister calls (a large, complex secondary concern). The two are separable.
Fix: The build script pattern is the unique educational value. Consider whether the NNS governance call is the right downstream to demonstrate it against, or whether a simpler canister interface would be clearer. At minimum, the README should make the build script pattern the headline.
rust/canister-snapshot-downloadTeaches: A scenario where stable memory is corrupted (represented by the minimal raw stable memory read/write canister), and how to download a snapshot, modify it, and re-upload to fix the corruption.
Problem: The canister code itself (
lib.rs, 21 lines) is a trivial stable memory demo without context. The teaching is in the surrounding scripts and docs. A developer readinglib.rslearns almost nothing about snapshots.Fix: Add inline comments explaining what this canister is demonstrating and why the stable memory layout matters for the snapshot scenario. Consider merging with
canister-snapshotsinto one coherent "canister lifecycle: snapshot and restore" example.rust/composite_queryTeaches: The
#[query(composite = true)]attribute for making inter-canister calls from a query context — reduces latency significantly for read-heavy multi-canister architectures.Problem: The example embeds a canister factory pattern (creating and installing partition canisters from Wasm bytes at runtime) alongside the composite query pattern. The two concepts are orthogonal, and the factory code adds complexity that distracts from the composite query point.
Fix: Strip or move the canister factory logic. Keep only the partition canister pattern needed to demonstrate
composite = true. Thegetvsget_updatecomparison is excellent and should be front and center.rust/evm_block_explorerTeaches (should be): Querying Ethereum block data via the EVM RPC canister, handling multi-provider consensus results (
#Consistent(#Ok),#Consistent(#Err),#Inconsistent).Problem: The example also includes
sign_message_with_ecdsaandsign_message_with_schnorrfunctions that have nothing to do with block exploration. The scope is incoherent — it's a block explorer and a key demo simultaneously.Fix: Remove or extract the signing functions. Keep only the block fetching and the three-way consensus result handling. The name should match the concept: this is about
eth_get_block_by_numberand multi-provider result handling.rust/face-recognitionTeaches: Running ONNX neural network inference on ICP via
ic_wasi_polyfill(WASI compatibility layer inside a canister), loading large model binaries in chunks via stable memory.Problem: The chunked model upload and WASI polyfill patterns are the ICP-specific teaching points, but they are buried under two ONNX model pipelines and the ML inference code. Developers building AI apps need to extract the infra patterns from the ML logic.
Fix: Add a dedicated comment section (or README section) explicitly naming the ICP-specific patterns: "1. How chunked stable memory upload works (lines X–Y). 2. How
ic_wasi_polyfill::init()provides WASI compatibility (line Z)."rust/hello_worldTeaches: Persisting a greeting prefix in a
StableBTreeMapCellviaMemoryManager, exposing aset_greetingupdate andgreetquery.Problem: The name says "hello world" but the code teaches stable memory persistence with
ic_stable_structures.backend_onlyis the actual hello world (4 lines, one query). A new developer openinghello_worldexpecting an entry point gets an intermediate stable-memory lesson.Fix: Rename to
persistent_greetingorstable_memory_greeting. Makebackend_onlythe primary entry point. Or explicitly add a README note: "This example teaches stable memory, not hello world. For the minimal starting point, seebackend_only."rust/icp_transferTeaches: Transferring ICP using the legacy
ic_ledger_typescrate —AccountIdentifier,Tokens,transfer().Problem: Same issue as
motoko/icp_transfer. The legacy API is correct for some use cases (exchange integrations, existing infrastructure) but should not be the first thing developers reach for.Fix: Add a prominent README note distinguishing legacy vs ICRC-1. Cross-link to
icrc_ledger.rust/photo_galleryTeaches: Implementing the
http_requestquery handler to serve binary content (images) from canister memory with cache headers via the HTTP gateway.Problem: Uses
add_skip_certification_header, which opts out of asset certification entirely. This is the lazy path and is not safe for production. There is no explanation of the tradeoff.Fix: Add a comment explaining the skip-certification choice: "This example uses
skip_certificationfor simplicity. In production, implement certified assets to cryptographically verify responses." Link tocertified-variablesguide or the asset canister pattern.rust/stake_neuron_from_cliTeaches: Programmatic NNS neuron staking from Rust using
ic-agent— computing the staking subaccount hash (SHA-256 with domain separation), building a principal-signed agent, calling governance.Problem: This is a Rust CLI binary using
ic-agent, not a canister. It is in a fundamentally different category from every other Rust example in the directory. Developers browsing canister examples will be confused when they find a CLI tool.Fix: Add a clear README header: "This is a Rust CLI program, not a canister. It demonstrates how to use
ic-agentfor programmatic interaction with an ICP canister from outside the IC." It is valuable in that category, just mislabeled.rust/vetkeys/basic_timelock_ibeTeaches: Canister-side decryption at a timed event — a canister holds its own transport key and uses a timer to trigger IBE key derivation and batch decryption of submitted ciphertexts. This is distinct from client-side decryption in
basic_ibe.Problem: The auction application scaffolding (lot status machines, bid tracking, tie-breaking logic) is ~350 lines around a ~50-line crypto core. The key pattern — a canister acting as its own decrypter — is buried. The dummy
vec![0; 32]transport key seed looks alarming without a comment explaining it is safe here (per-call ephemeral transport key).Fix: Add a comment explaining the dummy seed and why it's safe. Reduce the auction scaffolding or add explicit navigation comments pointing to the
decrypt_ciphertexts()function as "the core teaching content."rust/vetkeys/encrypted_notes_dapp_vetkdTeaches: Per-resource symmetric key derivation using vetKeys: the note ID (not user principal) is the key derivation input, so the same key is accessible to any authorized user of that note. Also: caching non-extractable AES keys in IndexedDB — the only example in the set showing this pattern.
Problem: The Motoko backend uses
mo:base(deprecated) andpreupgrade/postupgradehooks (old pattern). This makes it a bad Motoko reference even though the concept is sound.Fix: Migrate Motoko backend to
mo:coreandpersistent actor. The JavaScript pattern (IndexedDB caching of non-extractable keys) is genuinely unique and should be highlighted in the README.KEEP (61)
These examples teach something distinct and do it well enough to reference from docs.
hosting/
godot-html5-template— Teaches: any pre-built static output (here: a Godot HTML5 export) can be deployed to ICP via an asset canister with a four-line config. Serves game developers who want confirmation their engine output works on ICP.oisy-signer-demo— Teaches: the full ICRC signer standard (ICRC-29) flow — creating aSignerwithPostMessageTransport, wrapping anHttpAgentin aSignerAgentfor signed transactions, using anonymous agents for reads (no popup) and signer agents for writes (wallet popup). TheuseOisyWallet.jshook is well-commented production-quality code. Only example covering wallet integration standards.hosting/react— Teaches: React/Vite app deployed as an ICP asset canister. The entire concept is in theicp.yaml. Correctly minimal.hosting/static-website— Teaches: pure HTML/CSS/JS files deployed to ICP without any build tool. The no-Node-toolchain path is distinct fromreactand matters for developers not using a JS framework.hosting/unity-webgl-template— Same concept asgodot-html5-templatebut for Unity — the most widely used game engine. Distinct audience justifies a separate example despite structural similarity.wasm/
wasm/counter— The best-written example in the entire collection from a pure educational standpoint. 106 lines of commented.watdemonstrating: IC System API imports (msg_reply,msg_reply_data_append,msg_arg_data_size,msg_arg_data_copy), thecanister_query/canister_updateexport naming convention, manual Candid encoding with documented byte layout, and memory management. After reading this, a developer understands what Motoko and Rust CDKs are doing on their behalf. Irreplaceable as a System API reference.motoko/
hello_world— Simplest possible entry point. Every platform needs a true hello world. Teachpersistent actor+ one query function. Keep as the "step 1."who_am_i— 7 lines. Teachespublic query (message) funcandmessage.caller— the foundation of all access control on ICP. Essential for every developer.canister_logs— Teaches:Debug.printbehavior across update/query/timer contexts, intentional traps, and the difference between pre-trap logging and post-trap recovery. Each public function isolates one scenario.classes— Teaches: actor classes as instantiatable canister blueprints, thewith cyclessyntax, and sharded state distribution across dynamically created canisters. Foundational for multi-canister architecture.composite_query— Teaches:public composite query funcfor calling other canisters' query functions without consensus. The side-by-sidegetUpdatevsget(composite query) contrast makes the latency benefit concrete. Covers a distinct, non-obvious ICP capability.canister_factory— Teaches: the four actor class lifecycle modes (#new,#install,#upgrade,#reinstall) and when to use actor class management vs. management canister calls directly. Includes before/after state comparisons for upgrade vs. reinstall. Uniquely comprehensive canister lifecycle reference.evm_block_explorer— Teaches:EvmRpc.eth_getBlockByNumberand the three-way result type (#Consistent(#Ok),#Consistent(#Err),#Inconsistent) for multi-provider consensus. Good chain-fusion reference combining EVM RPC with ECDSA/Schnorr.filevault— Teaches: per-principal data isolation using nestedMap(principal → filename → blob chunks), chunked blob upload/retrieve. The principal-scoped pattern is fundamental to ICP security and is not as clearly shown in other examples.flying_ninja— Teaches: in-memory sorted leaderboard, bounded array with insert-sort, andRandom.blob()for client seeds. Concrete and relatable.hello_cycles— Teaches:Cycles.balance(),Cycles.available()/Cycles.accept()for capping incoming cycles, andwith cycles = amount+Cycles.refunded()for forwarding. The canonical cycles mechanics reference — no other example explains acceptance and forwarding this clearly.icrc2-swap— The best security-focused example in the collection. Teaches: the deposit-swap-withdraw pattern, why the swap itself must beawait-free for atomicity, and why withdrawal must debit-before-transfer (not the reverse) to prevent reentrancy. The inline comments explaining these design decisions are exceptional and rare in example code.llm_chatbot— Teaches: bothLLM.prompt()(single-turn) andLLM.chat()(multi-turn with message history) frommo:llm. 16 lines. On-chain AI is a differentiating ICP capability.low_wasm_memory— Teaches:system func lowmemory()hook for proactive memory pressure handling before an OOM trap. No other example covers this operational resilience pattern.parallel_calls— Teaches the critical ICP async performance pattern: fire all calls first, collect futures, then await them all (notawaitin a loop). The sequential vs. parallel contrast makes the difference concrete. The comment about calls failing under high load is an important practical note.pub-sub— Teaches: passing and storingshared funcreferences as inter-canister callbacks — idiomatic Motoko that enables pub-sub patterns without polling. The callback-as-field pattern is non-obvious and not demonstrated elsewhere.query_stats— Teaches:canister_status→query_statsfor runtime observability. Short, focused, unique topic.send_http_get— The canonical HTTPS GET outcall reference. Teaches:transformfunction pattern,max_response_byteswith cost explanation,is_replicated = ?truefor consensus, and cycle attachment. Inline comments are outstanding.#regionmarkers make it doc-ready.send_http_post— Companion tosend_http_get. Adds: request body encoding,Content-Typeheader,is_replicated = ?falsefor non-replicated mode with idempotency key explanation. The GET/POST split is justified because the replicated/non-replicated semantics differ.superheroes— The canonical CRUD reference. Create/read/update/delete on aMapwith auto-incrementing IDs. Query vs. update distinction. Clean, 39 lines.threshold-ecdsa— Canonical threshold ECDSA reference. Teaches:ecdsa_public_keyandsign_with_ecdsamanagement canister calls, the three key ID environments (local/test/production), and SHA-256 pre-hashing. Essential for any chain-key signing use case.threshold-schnorr— Canonical threshold Schnorr reference. Teaches both BIP340 (secp256k1, Bitcoin Taproot) and Ed25519 variants. BIP-341 taproot tweak is correctly isolated.basic_bitcoin— Definitive Bitcoin integration reference. Teaches: P2PKH / P2WPKH / P2TR address derivation, UTXO management, fee estimation via percentiles, iterative transaction construction for P2TR Taproot. The Bitcoin-specific complexity is inherent to the domain, not bad code. Correctly labeled advanced.rust/
backend_only— Correct hello world for Rust. Four lines, one query. The entry point.basic_bitcoin— Same assessment as motoko: definitive Bitcoin wallet reference, comprehensive, appropriately advanced.basic_ethereum— Teaches: ECDSA key derivation per principal, Ethereum address computation from secp256k1 public key, EIP-1559 transaction construction and signing viaalloy, single-provider vs. multi-provider broadcast. Complete Ethereum wallet pattern.canister-info— Teaches:canister_infomanagement canister API for retrieving canister change history, controller hierarchies, and deployment chain traversal. Unique observability patterns not covered elsewhere.canister-snapshots— Teaches: the value of snapshots via a creative approach — the canister has a deliberate, commented-and-flagged bug inremove_spam. After taking a snapshot, deploying the buggy upgrade, and observing the broken state, restoring the snapshot demonstrates the concept clearly. Memorable because of the intentional bug.canister_logs— Teaches:ic_cdk::print,println!,trapin update/query/timer contexts. Covers all log production paths.daily_planner— Good multi-concept integration example combiningStableBTreeMapwith customStorable(Candid-serialized), HTTPS outcalls with transform, and CRUD. Realistic application that shows how the pieces connect.exchange-rates— Teaches: calling the IC Exchange Rate Canister withCall::bounded_wait, attaching cycles, and decoding a typed response. Clean and focused.flying_ninja— Same as Motoko: concrete game leaderboard with sorted in-memory state andraw_rand()usage.guards— Essential security example. Teaches: RAII-based reentrancy prevention viaDrop-based guard, and the critical nuance that the guard is only effective acrossawaitpoints (not within a synchronous message). The comment explainingTrueAsyncCallvsFalseAsyncCall(poll-to-completion vs yield) is one of the best educational comments in the entire library.image-classification— Simpler ONNX entry point thanface-recognition. Teaches: loading an ONNX model atinit/post_upgrade,ic_wasi_polyfill::init()for WASI compatibility. Good first example for on-canister ML.inter-canister-calls— Outstanding quality. Teaches:Call::unbounded_waitvsbounded_wait,with_arg, typed decoding,is_clean_reject()/is_immediately_retryable()error handling, retry-with-deadline pattern (stubborn_set), and cycle attachment. Each function in the caller canister teaches one distinct aspect. The comments about messaging model nuances are developer-essential material.llm_chatbot— 20 lines,ic_llmcrate, bothprompt(single-turn) andchat(multi-turn). The simplest possible LLM entry point.low_wasm_memory— Teaches#[on_low_wasm_memory]hook. Fix the stale "Bitcoin canister" comment but keep otherwise.parallel_calls—future::join_allfor concurrent inter-canister calls. The practical failure note under high load is important.performance_counters— Teaches:instruction_counter()andcall_context_instruction_counter()acrossawaitboundaries and in composite queries. Side-by-side comparison of counter behavior is unique.periodic_tasks— Teaches:set_timer_interval(recommended) vs#[heartbeat](legacy) with identical logic so the tradeoffs are directly comparable. The heartbeat limitations note is correct and useful.qrcode— Teaches: CPU-intensive computation (QR code generation + PNG rendering + logo overlay) in a canister is viable. Both update and query endpoints.performance_counter(0)logging is a bonus.query_stats— Unique monitoring pattern: query stats fromcanister_status.receiving-icp— Teaches: computing a canister'sAccountIdentifierand subaccounts, querying ICP balance. Practical complement toicp_transfer.send_http_getandsend_http_post— Among the best-written examples in the collection. Both referenced under Motoko assessment — same high marks apply.simd— Teaches: Wasm SIMD128 in a Rust canister — naive, packed, auto-vectorized, and explicit SIMD implementations side by side withinstruction_counter()benchmarking. Essential for ML/compute-intensive developers.threshold-ecdsa— Canonical minimal threshold ECDSA reference for Rust. Key ID enum with three environment variants is the correct pattern.threshold-schnorr— Canonical Schnorr reference for Rust. BIP341 Tapscript correctly isolated inwasm_only.rs. Includes integration tests.unit_testable_rust_canister— The only example teaching DI-based unit testing for canisters: trait-based mocks,Arc<dyn Trait>,#[tokio::test]for async testing. Every serious Rust canister developer needs this pattern.vetkd— Minimal vetKeys backend reference:vetkd_public_keyandvetkd_derive_keyfor both symmetric key and IBE contexts. 87 lines, two use cases side by side.who_am_i— Canonicalmsg_caller()reference. 10 lines.x509— Unique, sophisticated PKI example. Teaches: using threshold ECDSA and Schnorr keys as a Certificate Authority, CSR parsing and signature verification, root + leaf X.509 certificate issuance. Represents a genuinely novel ICP capability. For advanced developers building PKI infrastructure.rust/vetkeys/
basic_bls_signing— Teaches:sign_with_blspath — per-user BLS12-381 key derivation, domain separator construction, on-chain signature storage, browser-side verification via@dfinity/vetkeys. Only BLS signing example.basic_ibe— The canonical, teachable IBE reference. Teaches the full round-trip:vetkd_public_key→IbeCiphertext.encrypt(publicKey, IbeIdentity.fromPrincipal(receiver))→vetkd_derive_key(transport_key)→EncryptedVetKey.decryptAndVerify()→IbeCiphertext.decrypt(). The code inmain.tsmaps one-to-one onto the protocol steps. Every other IBE-using example should link back to this.password_manager— Teaches: using theEncryptedMapsabstraction from theic-vetkeyscrate as a drop-in encrypted key-value store with access control. The contrast between the thin wrapper here and the raw API inencrypted_notes_dapp_vetkdis the key educational progression.password_manager_with_metadata— Teaches one specific, real-world pattern: atomically updating an encrypted value (EncryptedMaps) and its unencrypted metadata (StableBTreeMap) in a single update call. The diff vs.password_manageris the entire lesson. Narrow and correct.Structural observations
The "hello world" problem in Rust:
backend_only(4 lines, correct entry point) andhello_world(stable memory withMemoryManager, an intermediate topic) have inverted roles.hello_worldshould be renamed.vetKeys example architecture: The 6 examples (after removing
encrypted_chat) form a clean three-layer progression that is worth making explicit:basic_ibe,basic_bls_signingencrypted_notes_dapp_vetkd(raw API, resource-keyed),basic_timelock_ibe(canister-as-decrypter)password_manager,password_manager_with_metadataLegacy vs. ICRC-1 ICP transfers:
icp_transfer(both Motoko and Rust) covers the legacy ICP ledger API;icrc_ledger(to create) covers the ICRC-1 standard. Both are valid but serve different audiences —icp_transferfor exchange/infrastructure integrations,icrc_ledgerfor new code. They need clear cross-references.daily_plannerin both languages is an integration example that deliberately combines multiple concepts. It serves a different purpose from the focused single-concept examples. Both should be kept and positioned as "see how the pieces fit together."The
evm_block_explorerscope problem appears in both Motoko and Rust: a block explorer that also contains unrelated signing functions. Both need the same fix: remove or extract the signing.Strongest examples overall (code quality + educational clarity + unique concept):
wasm/counter,rust/guards,rust/inter-canister-calls,motoko/icrc2-swap,rust/send_http_get,rust/vetkeys/basic_ibe,motoko/parallel_calls.Docs integration mapping
Getting started
hello_world(both)greeting_function,query_call,update_callBackend development
superheroes(both) — rename todata_storecreate,read,update,delete,stable_statesend_http_get+send_http_post(both)get_request,transform,post_request,cycles_costperiodic_tasks(both — Mo version to create)recurring_timer,one_shot_timer,post_upgrade_reregisterrandom_mazeor newrandomness(both)get_entropy,bounded_random,usage_examplecert-var(both — Rs version to create)set_certified,get_with_certificate,verify_clientllm_chatbot(both)simple_prompt,multi_turn_chatCanister calls
inter-canister-calls(both — Mo version to create)basic_call,bounded_wait,error_handling,retry_patternparallel_calls(both)sequential_calls,parallel_calls,join_allpub-sub(Mo only — Motoko-specific pattern)publisher_register,publisher_publish,subscriber_callbackfrontend_agentto create (JS + both)agent_setup,query_call,update_call,auth_delegationFrontend development
hosting/reacticp_yaml,vite_confighosting/static-websiteicp_yamlhosting/photo-storage(after II auth added)asset_manager_setup,batch_upload,upload_progressrust/photo_gallery(after certification note added)http_request_handler,certified_headersAuthentication
who_am_i(both)ii_login,get_identity,actor_with_identity,whoami_callTesting
unit_testable_rust_canistertrait_definition,mock_implementation,unit_testtested_canister(both)pocket_ic_setup,deploy_and_call,state_assertionSecurity
icrc2-swap(Mo) +guards(Rs)atomic_swap,debit_before_transfer,reentrancy_guard,drop_implcanister-snapshots(Rs)pre_upgrade,post_upgrade,snapshot_restoreguards(Rs) + parts ofwho_am_icaller_check,raii_guardChain fusion
basic_bitcoin(both)generate_address,get_utxos,create_transaction,sign_and_sendbasic_ethereum(Rs)derive_eth_address,get_balance,build_transaction,sign_and_broadcastevm_block_explorer(both)eth_get_block,handle_consensus_resultthreshold-ecdsa(both)get_public_key,sign_message,verify_signaturethreshold-schnorr(both)bip340_sign,ed25519_sign,verifyToken transfers and payments
icrc_ledger(both) — replacestokenmania,token_transfer,token_transfer_fromdeploy_ledger,transfer,check_balance,approve,transfer_fromicp_transfer+receiving-icp(both)derive_account_id,transfer_icp,check_balanceicrc2-swap(Mo)deposit,atomic_swap,safe_withdrawhosting/oisy-signer-demosigner_setup,connect_wallet,signed_transfer,session_persistenceCanister management
canister_logs(both)debug_print,trap_log,timer_log,query_logcanister-info(Rs)get_canister_info,controller_historycanister-snapshots(Rs)pre_upgrade_state,buggy_upgrade,restore_snapshothello_cycles(Mo + Rs to create)check_balance,accept_cycles,forward_cycleslow_wasm_memory(both)low_memory_handler,heartbeat_fillquery_stats(both)get_query_statsperformance_counters(Rs)count_instructions,composite_query_countersbackend_wasm64(Rs)wasm64_config(build config, not code)simd(Rs)naive_matmul,simd_matmul,benchmarkEncryption (vetKeys)
vetkeys/basic_ibe(both)get_ibe_public_key,encrypt_message,get_decryption_key,decrypt_messagevetkeys/basic_bls_signing(both)sign_with_bls,domain_separator,verify_blsvetkeys/basic_timelock_ibe(Rs)encrypt_bid,canister_decrypt,timer_revealvetkeys/encrypted_notes_dapp_vetkd(both, after Mo fix)derive_note_key,store_encrypted,retrieve_and_decryptvetkeys/password_manager(both)init_encrypted_maps,insert_value,grant_access,get_encrypted_keyvetkeys/password_manager_with_metadata(both)insert_with_metadata,atomic_updateRelationship to developer-docs#44
Issue #44 defines the snippet pipeline: region markers in examples → remark plugin →
CodeExamplecomponent in docs. That pipeline is the right approach and Phase 1 implementation is underway.This assessment is the prerequisite for Phase 2 (adding region markers). The guide→example mapping above supersedes the aspirational mapping in issue #44. Specifically:
tokenmania,token_transfer, andtoken_transfer_from(all listed in update dfx version so example runs without error #44) are replaced by a singleicrc_ledgerexample with regions. The section is also renamed from "DeFi / tokens" to "Token transfers and payments"evm_block_explorerneeds scope fix before region markers are addedinter-canister-calls,periodic_tasks,cert-varall have Motoko gaps that must be filled before they can serve as dual-language doc examplessafe_calls,rate_limiter,safe_upgrades,tested_canister,ckbtc_deposit,sns_governed) are still gaps — docs for those guides should remain inline until examples existRecommended sequence:
CodeExamplecomponent in docs (Phase 1/3 of update dfx version so example runs without error #44, already in progress)<CodeExample>components incrementally