Skip to content

Commit 6e8f3e4

Browse files
marc0oloclaude
andauthored
feat: migrate hello_world and who_am_i to icp-cli (#1355)
* feat: add Codespaces support to who_am_i examples (pilot) Updates both Motoko and Rust who_am_i examples to use GitHub Codespaces instead of ICP Ninja for the one-click browser experience. devcontainer.json changes: - Image: marc0olo/icp-dev-env-motoko:dev / icp-dev-env-rust:dev - workspaceFolder: opens VS Code directly in the example directory - Port 8000 (icp-cli gateway) replaces port 4943 (dfx) - postStartCommand: icp network start -d (auto-starts on every resume) - postCreateCommand: mops install (Motoko only) - Adds stateful.runme extension for interactive README buttons README changes: - Replaces ICP Ninja badge with Open in GitHub Codespaces badge - Adds note that authentication uses production id.ai (PocketIC accepts mainnet signatures, so no local II needed) - Adds Runme action buttons: deploy, frontend, reset-deploy, info - Removes icp network stop (lifecycle handled by Codespace suspension) - Adds mainnet guidance section See #1345 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: add postAttachCommand to open README with Runme buttons on attach Adds `"postAttachCommand": "code README.md"` to both who_am_i devcontainer configs so the README with Runme action buttons opens automatically every time a Codespace is attached. Also adds a resume note to the Motoko README pointing users to github.com/codespaces. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: improve Codespace resume guidance in both who_am_i READMEs Clarifies that returning users should look for the "Open existing codespace" banner on the creation page, and adds the github.com/codespaces link to the Rust README (was already in Motoko). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: use code -r to scope VS Code window to example subdirectory workspaceFolder doesn't scope the Explorer in Codespaces; code -r reopens the current window rooted at the example folder, fixing both the sidebar view and the terminal working directory. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: move Codespaces devcontainers to repo root .devcontainer/ GitHub Codespaces only discovers devcontainer.json under .devcontainer/ at the repo root — per-example subdirectory .devcontainer/ folders are silently ignored, causing the devcontainer_path URL param to be discarded. Adds root-level .devcontainer/motoko-who-am-i/ and /rust-who-am-i/ configs and updates the Codespaces badge URLs in both READMEs accordingly. The per-example .devcontainer/ files are kept for local dev container use. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: replace code -r with code README.md, suppress noisy notifications - Removes code -r (caused double window reload since workspaceFolder now works correctly once devcontainer is properly discovered) - Opens README.md on attach so Runme buttons are immediately visible - Suppresses port 7865 (PocketIC internal port) auto-forward notification - Sets git.openRepositoryInParentFolders=always to avoid parent-repo prompt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: remove per-example .devcontainer directories Root-level .devcontainer/<name>/ configs handle both Codespaces and local dev container use. Per-example configs are redundant and create maintenance overhead across 46+ examples. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: Codespaces DX improvements for who_am_i examples - Fix ICP gateway rejecting API calls from Codespaces: override origin header in Vite proxy to localhost:8000 so the network launcher accepts requests from non-localhost forwarded domains - Add "Show URLs" Runme cell that constructs correct Codespaces-aware frontend and Candid UI URLs using $CODESPACE_NAME - Rename "Local development" section to "Codespace actions" and remove redundant "Install dependencies" cell (handled by postCreateCommand) - Set workbench.editorAssociations to open .md files in Runme directly, preventing the double README tab (preview + notebook) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: route agent to port 8000 in Codespaces, use ?canisterId= URLs - actor.js: detect .app.github.dev and route API calls directly to the port-8000 forwarded URL, bypassing the Vite proxy host check - README: reorder Codespace actions (Show URLs before dev server), use ?canisterId= query-param routing (works with Codespaces port forwarding), derive Candid UI URL from icp network status --json, remove icp environment cell Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: auto-deploy and open frontend URL on Codespace attach Add postAttach.sh scripts for both who_am_i devcontainers: - deploys canisters on first attach (guarded by canister status check, skipped on reconnects) - prints Frontend + Candid UI URLs to terminal - opens frontend in browser via `code --open-url` - opens README in editor Update README to reflect automatic deploy/open behaviour; simplify Codespace actions section accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: improve postAttach transparency with status messages Add clear echo output at each stage: network confirmation, deploy progress (with timing hint), deployment complete/skipped, URL building, and browser open notification. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: re-add redeploy cell to Codespace actions (preserves state) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: suppress port 7863 notification (PocketIC internal port) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: suppress port 7864 notification (Runme extension process) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: remove code --open-url (browser blocks programmatic tabs) URLs are printed to the terminal and are clickable via Cmd/Ctrl+click. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: root key fetch and broken-pipe in Codespaces actor.js: create HttpAgent explicitly and call fetchRootKey() when accessed via the ICP gateway directly (no ic_env cookie). Extend isLocalNetwork() to cover .app.github.dev so Codespaces URLs are treated as local. Make createBackendActor async accordingly. App.jsx: await createBackendActor. postAttach.sh: capture icp network status --json into a variable before piping to jq to avoid the broken-pipe panic; add __Candid_UI fallback for candid_ui_principal. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: use echo to pipe JSON to jq (printf omits trailing newline) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * revert: remove fetchRootKey logic from actor.js The asset canister serves the ic_env cookie (containing the root key) when the frontend is loaded directly from the ICP gateway, so the agent already has the correct root key. The explicit fetchRootKey call and async createBackendActor were unnecessary. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: add *.app.github.dev to gateway domains for Codespaces support Allows the ICP HTTP gateway to accept requests with Codespaces forwarded Host headers. If the gateway doesn't support wildcards, we'll need a dynamic postStart.sh approach instead. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * revert: remove Codespaces host workarounds from actor.js and vite.config.js getNetworkHost() and the origin header override were workarounds for the gateway rejecting non-localhost Host headers. The root cause is now fixed via gateway.domains in icp.yaml, so these are no longer needed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: inject Codespaces domain into icp.yaml via postStart.sh The wildcard *.app.github.dev caused the gateway to hang (PocketIC doesn't support wildcards). Replace with a postStart.sh script that injects the exact ${CODESPACE_NAME}-8000.app.github.dev domain into icp.yaml before starting the network. The modification is workspace- local and not committed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: centralize devcontainer scripts and add generic CODESPACE.md - Move postStart.sh and postAttach.sh to .devcontainer/scripts/ (shared by all examples); both devcontainer.json files now reference them directly - postStart.sh: generic gateway domain injection — handles both ii:true and non-ii icp.yaml layouts - postAttach.sh: fully generic via `icp project show` + jq — detects frontend vs backend canisters by recipe/sync type, shows correct URLs for each (frontend URL or Candid UI link) - Add .devcontainer/CODESPACE.md with Show URLs / Redeploy / Reset cells; symlinked into motoko/who_am_i and rust/who_am_i - Scope workbench.editorAssociations to CODESPACE.md only (not *.md) - Remove postCreateCommand (mops install) from motoko devcontainer - Use icp deploy --mode reinstall -y for reset instead of network restart Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor: extract URL display to show-urls.sh Move URL detection logic from postAttach.sh and CODESPACE.md into a dedicated script. All three cells in CODESPACE.md are now one-liners. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: clean up Codespace section in who_am_i READMEs Remove incorrect "open existing codespace" claim, drop Codespace actions (moved to CODESPACE.md), and remove em-dashes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: remove Runme, add startup editor suppression, document URL limitations - Remove stateful.runme extension from both devcontainer configs - Remove workbench.editorAssociations (no longer needed) - Add workbench.startupEditor: none to suppress auto-opening README.md - CODESPACE.md is now plain markdown: warns that icp deploy URLs do not work in Codespaces and explains the ?canisterId= limitation for non-SPA frontends Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: improve Codespace UX for who_am_i examples - Open CODESPACE.md immediately on attach (before deploy) and in preview mode - Always run icp deploy on attach (idempotent, accurate for both first start and resume) - Add setup-in-progress disclaimer to CODESPACE.md - Move non-SPA note to bottom, rename Redeploy section to Deploy / Redeploy - Replace invalid workbench.commandPalette.showAskInChat with editorAssociations for markdown preview Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: update port labels to ICP and Vite Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: add root devcontainer for local multi-example development Uses the combined Motoko + Rust image for contributors and explorers who clone the full repo. No lifecycle scripts — intended for local Dev Containers use, not Codespaces. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: use fully qualified rust-lang.rust-analyzer extension ID Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: update README with icp-cli, Codespaces, and Dev Containers - Replace dfx install instructions with icp-cli - Document GitHub Codespaces (per-example badges) and root Dev Container - Remove Gitpod reference - Fix all docs URLs to docs.internetcomputer.org - Demote ICP Ninja to a brief mention Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: remove ICP Ninja section and fix security best practices URL Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: remove NINJA_CONTRIBUTING.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: refurbish ADDING_AN_EXAMPLE.md - Remove ICP Ninja reference (NINJA_CONTRIBUTING.md deleted) - Replace dfx references with icp-cli - Add Codespaces devcontainer guidance for new examples Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: remove outdated portal submodule documentation section Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: remove ICP Ninja reference and update example submission guidance Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: add Codespaces support to hello_world examples - Add devcontainer configs for motoko-hello-world and rust-hello-world - Add CODESPACE.md symlinks - Replace ICP Ninja sections with Codespaces badge in both READMEs - Remove dfx.json, BUILD.md, and old .devcontainer from each example - Add hello_world.yml CI workflow using icp-cli - Remove hello_world entries from ninja_pr_checks.yml - Fix security best practices and icp-cli URLs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: add Makefiles with tests and CI workflows for hello_world and who_am_i hello_world: tests default greeting, setGreeting/set_greeting + updated output who_am_i: tests whoami returns a principal and is deterministic Creates who_am_i.yml CI workflow; removes hello_world and who_am_i from ninja_pr_checks.yml to avoid duplicate runs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: add workflow template, clarify npm run dev, update contributing guide - Add .github/workflow-template.yml as canonical starting point for new examples - Remove mops install from who_am_i CI (handled by icp deploy) - Separate npm run dev from deploy steps in who_am_i READMEs with explanation - Update ADDING_AN_EXAMPLE.md to reference template and Makefile pattern Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: handle icp.yaml without a network section in postStart.sh Fall back to appending a network block when neither ii: true nor mode: managed is present. Fixes gateway injection for examples like hello_world that have no network section in their icp.yaml. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: use correct networks.local structure when appending to icp.yaml The icp.yaml schema expects 'networks' (plural) with named entries, not a top-level 'network' field. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: networks is a sequence not a map in icp.yaml Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: add Vite devserver domain to gateway domains in postStart.sh Includes the port 5173 forwarded domain so the ICP gateway accepts requests proxied through the Vite dev server in Codespaces. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: ensure network is running in postAttach.sh Adds a defensive icp network start -d before deploy so the Codespace recovers if postStart.sh failed or the network process didn't survive. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: wait for ICP network to be ready before deploying icp network start -d returns immediately but the replica takes a moment to be ready. Poll localhost:8000/api/v2/status until it responds before running icp deploy. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: remove redundant network start and polling from postAttach.sh postStartCommand completes before postAttachCommand runs, so the network is guaranteed ready by postStart.sh. The band-aid was masking errors. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: wait for network readiness in postStart.sh before returning icp network start -d may return before the replica is ready to accept connections. Poll /api/v2/status so postStartCommand only completes once the network is actually up, guaranteeing postAttach can deploy. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: add set -e to lifecycle scripts and remove unnecessary polling icp network start -d already blocks until the network is ready. set -e ensures failures are visible immediately rather than silently continuing to the next command. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor: rename canisters to backend/frontend in who_am_i examples Rename internet_identity_app_backend → backend and internet_identity_app_frontend → frontend in both Motoko and Rust who_am_i examples, including src directories, .did files, icp.yaml, Cargo.toml, Makefile, vite.config.js, actor.js, package.json, .gitignore, and README. Also removes ICP Ninja artifacts (dfx.json, BUILD.md) and simplifies vite.config.js by dropping the dfx fallback. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: bump moc/core, use --default-persistent-actors, pin recipe fix branch - moc 1.5.1 → 1.8.2, core 2.4.0 → 2.5.0 - Add --default-persistent-actors to moc args so the persistent keyword is no longer needed in main.mo - Pin Motoko recipe to fix/motoko-mops-moc-args branch until dfinity/icp-cli-recipes#26 merges and a stable release is cut Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: add AGENTS.md and CLAUDE.md with example structure guidelines AGENTS.md is the primary source of agent instructions covering: canonical example layout, icp.yaml / mops.toml / Cargo.toml patterns, Makefile requirements, devcontainer and CI workflow templates, README structure, dfx→icp-cli migration checklist, and pending items (images, Motoko recipe version). CLAUDE.md delegates to AGENTS.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: instruct agents to fetch ICP skills before working Adds a Skills section at the top of AGENTS.md pointing to the live skills registry at skills.internetcomputer.org. Lists the relevant skills (icp-cli, icp-cli/dfx-migration, motoko, mops-cli, internet-identity, asset-canister) and establishes that skills take precedence over general knowledge where they overlap. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: add paths filter to ninja_pr_checks workflow Without a paths filter, changing the workflow file (e.g. removing hello_world and who_am_i which now use icp-cli) triggers the run_all_examples self-trigger, causing all ninja examples to run on unrelated PRs. Enumerating the exact ninja-managed paths ensures the workflow only fires when relevant example code or the workflow file itself changes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: pin Motoko recipe to immutable commit SHA Both Motoko examples now point to the specific commit of the fix branch rather than the branch name, which is mutable. Swap to a stable @dfinity/motoko release tag once dfinity/icp-cli-recipes#26 ships. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * refactor: adopt new Motoko recipe format (v5 schema) The new recipe only needs `name` in icp.yaml. Move `main`, `candid`, and per-canister args into mops.toml under [canisters.<name>]. - hello_world: bump moc 1.5.1→1.8.2, core 2.4.0→2.5.0, add --default-persistent-actors, add [canisters.backend], drop `persistent` keyword from app.mo - who_am_i: add [canisters.backend] to existing mops.toml - Both READMEs: update .did regeneration command to `mops build backend --idl` - AGENTS.md: update icp.yaml and mops.toml reference examples Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: remove deleted examples from ninja_pr_checks paths filter tokenmania, nft-creator (Motoko) and tokenmania (Rust) were removed from master; drop their path entries to keep the filter in sync. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: switch to official dfinity icp-dev-env images v0.1.0 Replace ghcr.io/marc0olo/icp-dev-env-*:dev with the now-published ghcr.io/dfinity/icp-dev-env-*:0.1.0 in all devcontainer configs and CI workflows. Update AGENTS.md to reflect images are live. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: clarify why icp deploy URLs don't work in Codespaces Be specific that it's the subdomain form (<canister-id>.localhost:8000) that breaks, and why: GitHub's TLS certificate only covers one subdomain level. Link to the open GitHub community issue tracking this limitation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: improve URL command wording in CODESPACE.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: migrate hello_world and who_am_i to icp-cli, drop Codespaces support - dfx → icp-cli: icp.yaml, mops.toml, canister renames to backend/frontend, README deploy instructions updated throughout - Remove Codespaces: drop 4 per-example devcontainers, CODESPACE.md, lifecycle scripts; remove Codespaces badges and references from all READMEs - Keep root devcontainer (.devcontainer/devcontainer.json) for local VS Code use - CI: hello_world.yml and who_am_i.yml workflows using official ghcr.io/dfinity/icp-dev-env-{motoko,rust}:0.1.0 images - Makefiles with test targets for all four examples - README improvements: icp-cli-templates pointer, example references, language-specific prerequisites, correct Candid regeneration commands, icp network stop guidance, npm run dev guidance - AGENTS.md: updated structure, removed Codespaces instructions, fixed Motoko recipe SHA, added reference examples section - ninja_pr_checks.yml: scoped to ninja-managed paths only Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: add devcontainer removal step to migration checklist Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: remove hardcoded workspaceFolder from root devcontainer /workspaces/examples only works if the repo is cloned into a folder named exactly "examples". Omitting it lets VS Code use whatever path it mounts the project at, which is correct for local use. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: remove CODESPACE.md files, fix AGENTS.md recipe SHA and prerequisites - Remove CODESPACE.md from all four examples (Codespaces support dropped) - Show actual pinned SHA in AGENTS.md Motoko recipe template with TODO comment, replacing misleading @dfinity/motoko@vX.Y.Z placeholder - Fix prerequisite checkboxes in README template: [ ] -> [x] Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * style: use plain bullets for prerequisites instead of checkboxes Checkbox syntax is for task tracking, not requirements lists. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: clarify educational focus and acceptance criteria for new examples New examples must demonstrate a specific ICP concept, have a clear home in the developer documentation, and be agreed with the DX team. Random or general-purpose examples are not accepted. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 51952c3 commit 6e8f3e4

65 files changed

Lines changed: 780 additions & 730 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.devcontainer/devcontainer.json

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "ICP Examples (Motoko + Rust)",
3+
"image": "ghcr.io/dfinity/icp-dev-env-all:0.1.0",
4+
"forwardPorts": [8000, 5173],
5+
"portsAttributes": {
6+
"8000": {
7+
"label": "ICP",
8+
"onAutoForward": "ignore"
9+
},
10+
"5173": {
11+
"label": "Vite",
12+
"onAutoForward": "openBrowser"
13+
}
14+
},
15+
"customizations": {
16+
"vscode": {
17+
"extensions": [
18+
"dfinity-foundation.vscode-motoko",
19+
"rust-lang.rust-analyzer"
20+
],
21+
"settings": {
22+
"git.openRepositoryInParentFolders": "always",
23+
"workbench.startupEditor": "none",
24+
"workbench.editorAssociations": {
25+
"*.md": "vscode.markdown.preview.editor"
26+
}
27+
}
28+
}
29+
}
30+
}

.github/CONTRIBUTING.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
# Contributing
22

3-
> For ICP Ninja: check [NINJA_CONTRIBUTING.md](./../NINJA_CONTRIBUTING.md) for how to contribute a project to ICP Ninja.
4-
53
Thank you for your interest in contributing to example apps for the Internet Computer.
64
By participating in this project, you agree to abide by our [Code of Conduct](./CODE_OF_CONDUCT.md).
75

@@ -116,4 +114,4 @@ To open a new issue:
116114
117115
### Submitting your own example
118116
119-
We're not accepting community examples at this time -- we have something better planned.
117+
See [ADDING_AN_EXAMPLE.md](./../ADDING_AN_EXAMPLE.md) for guidelines on how to structure and submit a new example.

.github/workflow-template.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Workflow template for ICP examples.
2+
# Copy this file to .github/workflows/<example_name>.yml and replace the placeholders.
3+
#
4+
# PLACEHOLDERS:
5+
# <example_name> e.g. hello_world
6+
# <language> motoko | rust
7+
# <image> ghcr.io/dfinity/icp-dev-env-motoko | ghcr.io/dfinity/icp-dev-env-rust
8+
9+
name: <example_name>
10+
11+
on:
12+
push:
13+
branches:
14+
- master
15+
pull_request:
16+
paths:
17+
- <language>/<example_name>/**
18+
- .github/workflows/<example_name>.yml
19+
20+
concurrency:
21+
group: ${{ github.workflow }}-${{ github.ref }}
22+
cancel-in-progress: true
23+
24+
jobs:
25+
<language>-<example_name>:
26+
runs-on: ubuntu-24.04
27+
container: <image>
28+
steps:
29+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
30+
- name: Deploy and test
31+
working-directory: <language>/<example_name>
32+
run: |
33+
icp network start -d
34+
icp deploy
35+
make test

.github/workflows/hello_world.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: hello_world
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
paths:
9+
- motoko/hello_world/**
10+
- rust/hello_world/**
11+
- .github/workflows/hello_world.yml
12+
13+
concurrency:
14+
group: ${{ github.workflow }}-${{ github.ref }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
motoko-hello_world:
19+
runs-on: ubuntu-24.04
20+
container: ghcr.io/dfinity/icp-dev-env-motoko:0.1.0
21+
steps:
22+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
23+
- name: Deploy and test
24+
working-directory: motoko/hello_world
25+
run: |
26+
icp network start -d
27+
icp deploy
28+
make test
29+
30+
rust-hello_world:
31+
runs-on: ubuntu-24.04
32+
container: ghcr.io/dfinity/icp-dev-env-rust:0.1.0
33+
steps:
34+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
35+
- name: Deploy and test
36+
working-directory: rust/hello_world
37+
run: |
38+
icp network start -d
39+
icp deploy
40+
make test

.github/workflows/ninja_pr_checks.yml

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,50 @@ on:
44
pull_request:
55
branches:
66
- master
7+
paths:
8+
- 'hosting/**'
9+
- 'motoko/backend_only/**'
10+
- 'motoko/canister_logs/**'
11+
- 'motoko/classes/**'
12+
- 'motoko/basic_bitcoin/**'
13+
- 'motoko/daily_planner/**'
14+
- 'motoko/evm_block_explorer/**'
15+
- 'motoko/filevault/**'
16+
- 'motoko/flying_ninja/**'
17+
- 'motoko/llm_chatbot/**'
18+
- 'motoko/query_stats/**'
19+
- 'motoko/send_http_get/**'
20+
- 'motoko/send_http_post/**'
21+
- 'motoko/superheroes/**'
22+
- 'motoko/threshold-ecdsa/**'
23+
- 'motoko/threshold-schnorr/**'
24+
- 'rust/backend_only/**'
25+
- 'rust/backend_wasm64/**'
26+
- 'rust/basic_bitcoin/**'
27+
- 'rust/canister-info/**'
28+
- 'rust/canister_logs/**'
29+
- 'rust/basic_ethereum/**'
30+
- 'rust/candid_type_generation/**'
31+
- 'rust/daily_planner/**'
32+
- 'rust/evm_block_explorer/**'
33+
- 'rust/flying_ninja/**'
34+
- 'rust/guards/**'
35+
- 'rust/llm_chatbot/**'
36+
- 'rust/performance_counters/**'
37+
- 'rust/periodic_tasks/**'
38+
- 'rust/qrcode/**'
39+
- 'rust/query_stats/**'
40+
- 'rust/send_http_get/**'
41+
- 'rust/send_http_post/**'
42+
- 'rust/simd/**'
43+
- 'rust/threshold-ecdsa/**'
44+
- 'rust/unit_testable_rust_canister/**'
45+
- 'rust/photo_gallery/**'
46+
- 'rust/inter-canister-calls/**'
47+
- 'rust/x509/**'
48+
- 'rust/receiving-icp/**'
49+
- 'rust/exchange-rates/**'
50+
- '.github/workflows/ninja_pr_checks.yml'
751

852
concurrency:
953
group: ninja-pr-checks-${{ github.workflow }}-${{ github.ref }}
@@ -41,15 +85,13 @@ jobs:
4185
["EVM Block Explorer (Motoko)"]="motoko/evm_block_explorer"
4286
["FileVault (Motoko)"]="motoko/filevault"
4387
["Flying Ninja (Motoko)"]="motoko/flying_ninja"
44-
["Hello World (Motoko)"]="motoko/hello_world"
4588
["LLM Chatbot (Motoko)"]="motoko/llm_chatbot"
4689
["Query Stats (Motoko)"]="motoko/query_stats"
4790
["Send HTTP Get (Motoko)"]="motoko/send_http_get"
4891
["Send HTTP Post (Motoko)"]="motoko/send_http_post"
4992
["Superheroes (Motoko)"]="motoko/superheroes"
5093
["Threshold ECDSA (Motoko)"]="motoko/threshold-ecdsa"
5194
["Threshold Schnorr (Motoko)"]="motoko/threshold-schnorr"
52-
["Who Am I (Motoko)"]="motoko/who_am_i"
5395
["Rust backend (Rust)"]="rust/backend_only"
5496
["Rust backend Wasm64 (Rust)"]="rust/backend_wasm64"
5597
["Basic Bitcoin (Rust)"]="rust/basic_bitcoin"
@@ -61,7 +103,6 @@ jobs:
61103
["EVM Block Explorer (Rust)"]="rust/evm_block_explorer"
62104
["Flying Ninja (Rust)"]="rust/flying_ninja"
63105
["Guards (Rust)"]="rust/guards"
64-
["Hello World (Rust)"]="rust/hello_world"
65106
["LLM Chatbot (Rust)"]="rust/llm_chatbot"
66107
["Performance Counters (Rust)"]="rust/performance_counters"
67108
["Periodic Tasks (Rust)"]="rust/periodic_tasks"
@@ -72,7 +113,6 @@ jobs:
72113
["SIMD (Rust)"]="rust/simd"
73114
["Threshold ECDSA (Rust)"]="rust/threshold-ecdsa"
74115
["Unit Testable Canister (Rust)"]="rust/unit_testable_rust_canister"
75-
["Who Am I (Rust)"]="rust/who_am_i"
76116
["Photo Gallery (Rust)"]="rust/photo_gallery"
77117
["Inter-canister calls (Rust)"]="rust/inter-canister-calls"
78118
["X.509 (Rust)"]="rust/x509"

.github/workflows/who_am_i.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: who_am_i
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
pull_request:
8+
paths:
9+
- motoko/who_am_i/**
10+
- rust/who_am_i/**
11+
- .github/workflows/who_am_i.yml
12+
13+
concurrency:
14+
group: ${{ github.workflow }}-${{ github.ref }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
motoko-who_am_i:
19+
runs-on: ubuntu-24.04
20+
container: ghcr.io/dfinity/icp-dev-env-motoko:0.1.0
21+
steps:
22+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
23+
- name: Deploy and test
24+
working-directory: motoko/who_am_i
25+
run: |
26+
icp network start -d
27+
icp deploy
28+
make test
29+
30+
rust-who_am_i:
31+
runs-on: ubuntu-24.04
32+
container: ghcr.io/dfinity/icp-dev-env-rust:0.1.0
33+
steps:
34+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
35+
- name: Deploy and test
36+
working-directory: rust/who_am_i
37+
run: |
38+
icp network start -d
39+
icp deploy
40+
make test

ADDING_AN_EXAMPLE.md

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,49 @@
11
# How to add a new example
22

3-
> For ICP Ninja: check [NINJA_CONTRIBUTING.md](./NINJA_CONTRIBUTING.md) for how to contribute a project to ICP Ninja.
3+
## Purpose and acceptance criteria
4+
5+
Examples in this repository have an **educational focus**. Each example is intended to demonstrate a specific ICP capability or pattern, and should be suitable for reference from the [ICP developer documentation](https://docs.internetcomputer.org).
6+
7+
**We do not accept general-purpose or arbitrary examples.** Before opening a PR, confirm that:
8+
9+
- The example demonstrates a distinct ICP concept not already covered by an existing example.
10+
- There is a clear home for it in the developer documentation (an existing or planned guide, tutorial, or reference page).
11+
- The DFINITY DX team has agreed to maintain it long-term.
12+
13+
If you are unsure whether your example fits, open an issue first to discuss it with the maintainers before investing time in an implementation.
14+
15+
---
416

517
Each example should be available in both Rust and Motoko variations, implementing the same Candid interface (and, ideally, semantics).
618

7-
To illustrate the pattern, this repo now contains one such example, project `hello_world`:
19+
To illustrate the pattern, this repo contains one such example, project `hello_world`:
820

9-
`motoko/hello_world`
10-
`rust/hello_world`
21+
```
22+
motoko/hello_world
23+
rust/hello_world
24+
```
1125

12-
When adding a new `dfx` generated project, make sure to delete its GitHub metadata files (`.gitignore`, `.git` etc).
26+
When adding a new project, make sure to delete any generated GitHub metadata files (`.gitignore`, `.git` etc).
1327

1428
Each project should include a language-specific README.md that also links to the corresponding README.md of its counterpart in another language, making it easy for language-curious readers to explore both implementations.
1529

1630
## CI
1731

18-
Apart from the standard `dfx` material, each project should provide a `Makefile` used by GitHub Actions CI to run (very) basic tests.
32+
Each project should provide a `Makefile` with a `test` target that runs basic canister tests using `icp canister call`. Each example also needs a GitHub Actions workflow file at `.github/workflows/<example_name>.yml`.
1933

20-
For each example, there is a single CI file with four build actions to produce Darwin and Linux builds and tests of the Motoko/Rust, projects, such as:
34+
Use the workflow template as a starting point:
2135

2236
```
23-
.github/workflows/hello_world.yml
37+
.github/workflow-template.yml
2438
```
2539

26-
Implementing the GitHub action will ensure it runs in CI and helps keep examples in sync with releases of `dfx`.
27-
28-
## Documentation
40+
Copy it, replace the placeholders, and add the appropriate container image:
2941

30-
For your new example to be included in the ICP developer documentation, make sure you update the `samples` submodule in the portal repository to point to the latest commit in this examples repository using the following command:
31-
32-
```bash
33-
git submodule update --remote submodules/samples
34-
```
42+
- Motoko: `ghcr.io/dfinity/icp-dev-env-motoko`
43+
- Rust: `ghcr.io/dfinity/icp-dev-env-rust`
3544

36-
After you run this command, commit the changes to a new PR to have them merged into the portal repo.
45+
See `hello_world` and `who_am_i` for reference implementations. Workflows run on Linux only using container images — no provision scripts needed.
3746

38-
## Issues
47+
## Notes
3948

40-
While this structure leads to some duplication (especially shared components like frontend code) it ensures that Motoko users can focus solely on Motoko-specific content, and likewise for Rust users. It also enables easily finding language-specific examples when a given use case is not easily supported in the other language.
49+
While this structure leads to some duplication (especially shared frontend code) it ensures that Motoko users can focus solely on Motoko-specific content, and likewise for Rust users. It also enables easily finding language-specific examples when a given use case is not easily supported in the other language.

0 commit comments

Comments
 (0)