AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified Apache-2.0 Self-run

Icp Cli

skill-dfinity-icskills-icp-cli · by dfinity

Guides use of the icp command-line tool for building and deploying Internet Computer applications. Covers project configuration (icp.yaml), recipes, environments, canister lifecycle, identity management, and bundling a project into a self-contained .icp package (icp project bundle). Use when building, deploying, or managing any IC project. Use when the user mentions icp, dfx, canister deployment,…

— No reviews yet
0 installs
37 views
0.0% view→install

Install

$ agentstack add skill-dfinity-icskills-icp-cli

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • ✓ Prompt-injection patterns
  • ✓ Secret / credential exfiltration
  • ✓ Dangerous shell & filesystem operations
  • ✓ Untrusted network calls
  • ✓ Known-malicious package signatures

What it can access

  • ✓ Network access No
  • ✓ Filesystem access No
  • ✓ Shell / process execution No
  • ● Environment & secrets Used
  • ✓ Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-dfinity-icskills-icp-cli)

Reliability & compatibility

✓ Security review passed
0 installs to date
— no reviews yet
● 2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Icp Cli? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

ICP CLI

What This Is

The icp command-line tool builds and deploys applications on the Internet Computer. It replaces the legacy dfx tool with YAML configuration, a recipe system for reusable build templates, and an environment model that separates deployment targets from network connections. Never use dfx — always use icp.

Before generating any icp command not explicitly documented here, run icp --help or icp --help to verify the command and its flags exist. Do not infer flags from dfx equivalents — the CLIs are not flag-compatible.

Installation

npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm

ic-wasm is required when using official recipes (@dfinity/rust, @dfinity/motoko, @dfinity/asset-canister) — they depend on it for optimization and metadata embedding. Requires Node.js >= 22. Also available via Homebrew and shell script installer — see the icp-cli releases.

Linux note: On minimal installs, you may need system libraries: sudo apt-get install -y libdbus-1-3 libssl3 ca-certificates (Ubuntu/Debian) or sudo dnf install -y dbus-libs openssl ca-certificates (Fedora/RHEL).

Prerequisites

  • For Rust canisters: rustup target add wasm32-unknown-unknown
  • For Motoko canisters: npm i -g ic-mops and a mops.toml at the project root with the Motoko compiler version and a [canisters] entry:

```toml [toolchain] moc = "1.9.0"

[canisters.backend] main = "src/backend/main.mo" `` The @dfinity/motoko@v5+ recipe compiles via mops build . The canister name in icp.yaml must exactly match a key in [canisters] — a missing or mismatched key causes mops build to fail with No Motoko canisters found in mops.toml configuration (see Pitfall 17). Without mops.toml, the recipe fails because mops is not found. Templates include mops.toml automatically; for manual projects, create it before running icp build. Load mops-cli for [canisters] configuration options, dependency management, and mops build` details.

Common Pitfalls

  1. Using dfx instead of icp. The dfx tool is legacy. All commands have icp equivalents — see references/dfx-migration.md for the full command mapping. Never generate dfx commands or reference dfx documentation. Configuration uses icp.yaml, not dfx.json — and the structure differs: canisters are an array of objects, not a keyed object.
  1. Using --network ic to deploy to mainnet. icp-cli uses environments, not direct network targeting. The correct flag is -e ic (short for --environment ic).

``bash # Wrong icp deploy --network ic # Correct icp deploy -e ic ` Note: -n / --network targets a network directly and works with canister IDs (principals). Use -e / --environment when referencing canisters by name. For token and cycles operations, use -n` since they don't reference project canisters.

  1. Using a recipe without a version pin. icp-cli rejects unpinned recipe references. Always include an explicit version. Official recipes are hosted at dfinity/icp-cli-recipes.

```yaml # Wrong — rejected by icp-cli recipe: type: "@dfinity/rust"

# Correct — pinned version recipe: type: "@dfinity/rust@v3.2.0" ```

  1. Writing manual build steps when a recipe exists. Official recipes handle Rust, Motoko, and asset canister builds. Use recipe: { type: "@dfinity/rust@v3.2.0", configuration: { package: backend } } instead of writing shell commands in build.steps.
  1. Not committing .icp/data/ to version control. Mainnet canister IDs are stored in .icp/data/mappings/.ids.json. Losing this file means losing the mapping between canister names and on-chain IDs. Always commit .icp/data/ — never delete it. Add .icp/cache/ to .gitignore (it is ephemeral and rebuilt automatically). If you have environments using a connected network that gets reset frequently you can add those specific environment mapping files to .gitignore. Never add the entire .icp or .icp/data directory to gitignore.
  1. Using icp identity use instead of icp identity default. The dfx command dfx identity use became icp identity default (setter). icp identity default with no argument is the getter — it prints the current default identity, equivalent to dfx identity whoami. The command icp identity use does not exist. Similarly, dfx identity get-principal became icp identity principal, and dfx identity remove became icp identity delete.
  1. Confusing networks and environments. A network is a connection endpoint (URL). An environment combines a network + canisters + settings. You deploy to environments (-e), not networks. Multiple environments can target the same network with different settings (e.g., staging and production both on ic).
  1. Writing networks or environments as a YAML map instead of an array. Both networks and environments are arrays of objects in icp.yaml, not maps:

```yaml # Wrong — map syntax networks: local: mode: managed environments: staging: network: ic

# Correct — array syntax networks:

  • name: local

mode: managed environments:

  • name: staging

network: ic canisters: [backend, frontend] ```

  1. Forgetting that local networks are project-local. Unlike dfx which runs one shared global network, icp-cli runs a local network per project. You must run icp network start -d in your project directory before deploying locally. The local network auto-starts with system canisters and seeds accounts with ICP and cycles. Stop it when done:

``bash icp network start -d # start background network icp deploy # build + deploy + sync icp network stop # stop when done ``

  1. Not specifying build commands for asset canisters. dfx automatically runs npm run build for asset canisters. icp-cli requires explicit build commands in the recipe configuration:

```yaml canisters:

  • name: frontend

recipe: type: "@dfinity/asset-canister@v2.2.1" configuration: dir: dist build:

  • npm install
  • npm run build

```

  1. Expecting output_env_file or .env with canister IDs. dfx writes canister IDs to a .env file (CANISTER_ID_BACKEND=...) via output_env_file. icp-cli does not generate .env files. Instead, it injects canister IDs as environment variables (PUBLIC_CANISTER_ID:) directly into canisters during icp deploy. Frontends read these from the ic_env cookie set by the asset canister. Remove output_env_file from your config and any code that reads CANISTER_ID_* from .env — use the ic_env cookie instead (see Canister Environment Variables below).
  1. Expecting dfx generate for TypeScript bindings. icp-cli does not have a dfx generate equivalent. Use @icp-sdk/bindgen (>= 0.3.0) with @icp-sdk/core (>= 5.0.0 — there is no 0.x or 1.x release) to generate TypeScript bindings from .did files at build time. Use outDir: "./src/bindings" so imports are clean (e.g., ./bindings/backend). The .did file must exist on disk — either commit it to the repo, or generate it with icp build first (recipes auto-generate it when candid is not specified). See references/binding-generation.md for the full Vite plugin setup.
  1. Passing { agent } to createActor from @icp-sdk/bindgen. The old @dfinity/agent pattern was createActor(canisterId, { agent }). The @icp-sdk/bindgen pattern is createActor(canisterId, { agentOptions: { host, rootKey } }) — the binding creates the agent internally. Passing { agent } to the new API silently creates an anonymous identity — no error is thrown, but calls return empty data or access denied. See references/binding-generation.md for the correct pattern.
  1. Mixing canister-level fields across config styles. When using a recipe, the only valid canister-level fields are name, recipe, sync, settings, and init_args. Fields like candid, build, or wasm are not valid at canister level alongside a recipe — recipe-specific options go inside recipe.configuration. When using bare build (no recipe), valid canister-level fields are name, build, sync, settings, and init_args. The field init_arg_file does not exist — use init_args.path instead (e.g., init_args: { path: ./args.bin, format: bin }). For the authoritative field reference, consult the icp-cli configuration reference.

```yaml # Wrong — candid is not a canister-level field when using a recipe canisters:

  • name: backend

candid: backend/backend.did recipe: type: "@dfinity/rust@v3.2.0" configuration: package: backend

# Correct — candid goes inside recipe.configuration canisters:

  • name: backend

recipe: type: "@dfinity/rust@v3.2.0" configuration: package: backend candid: backend/backend.did ```

  1. Placing mops.toml where mops cannot find it. mops searches upward from the build working directory. Where to place mops.toml depends on how the canister is defined:
  • Inline canisters (defined directly in icp.yaml): build cwd is the project root. Place mops.toml at the project root next to icp.yaml. A mops.toml in src/backend/ will not be found.
  • Path-based canisters (referenced via canisters/* or ./my-canister, each with its own canister.yaml): build cwd is the canister directory. Place mops.toml in each canister's directory for per-canister dependencies and compiler versions, or omit it to fall back to a shared mops.toml in a parent directory.

When mops.toml is not found, mops build fails because it cannot locate the project configuration. When mops.toml exists but is missing the matching [canisters.] entry, see Pitfall 17.

  1. Misunderstanding Candid file generation with recipes. Binding generation tools (e.g. @icp-sdk/bindgen) require a .did file at a known path on disk. Where to configure it depends on the recipe:

Rust — candid goes inside recipe.configuration in icp.yaml:

  • If specified: the file must already exist. The recipe uses it as-is and does not generate one.
  • If omitted: the recipe auto-generates the .did via candid-extractor into the build cache (no predictable project path).

To generate and commit it, then add candid: backend/backend.did inside recipe.configuration: ``bash cargo install candid-extractor # one-time setup icp build backend candid-extractor target/wasm32-unknown-unknown/release/backend.wasm > backend/backend.did ``

Motoko (v5 recipe) — mops build auto-generates the .did to .mops/.build/.did.

  • No binding generation needed — nothing to do. The generated .did in .mops/.build/ is sufficient; do not commit it.
  • Binding generation needed — commit a .did at a stable path and keep it in sync:

``bash mops build backend cp .mops/.build/backend.did backend/backend.did ` Point the binding tool's config (e.g. @icp-sdk/bindgen's didFile) at backend/backend.did. **After any interface change, re-run both commands** — mops build always writes to .mops/.build/` and does not update the committed file automatically.

  1. Missing or mismatched [canisters] key in mops.toml. The @dfinity/motoko@v5+ recipe calls mops build , where the name comes from the name field in icp.yaml. mops build requires a matching [canisters.] entry in mops.toml. If the entry is absent or the key does not exactly match (including casing), the build fails with:

`` No Motoko canisters found in mops.toml configuration ` Add the matching entry — the key must equal the name: value in icp.yaml: `toml [canisters.backend] main = "src/backend/main.mo" ``

  1. Port 8000 already in use when starting the local network. Two scenarios:

Scenario A — another icp-cli project holds the port. Stop that project's network using --project-root-override (a global flag available on all commands): ``bash icp network stop --project-root-override /path/to/other-project ` To run both networks at once instead of stopping one — e.g. parallel git worktrees — set gateway.port: 0` so each gets a free port. See "Parallel local networks (git worktrees)" under How It Works.

Scenario B — a non-icp service holds the port. Configure an alternate port in icp.yaml and read the actual URLs dynamically via icp network status --json rather than hardcoding localhost:8000: ```yaml networks:

  • name: local

mode: managed gateway: port: 8001 `` `bash icp network status --json # returns gateway URL, replica URL, etc. ``

  1. icp new hangs in CI without --silent. Without --define flags, icp new launches an interactive prompt that blocks indefinitely in non-interactive environments. Always pass --subfolder, --define, and --silent for scripted use:

``bash icp new my-project --subfolder rust --define project_name=my-project --silent ``

  1. Using the anonymous identity on mainnet. The local network seeds all managed identities — including the anonymous identity, which is the default — with ICP and cycles on start, so local development works out of the box with no identity or cycles setup required. On mainnet this does not apply, and the anonymous identity should never be used: it is shared by anyone, meaning ICP sent to it is publicly accessible and canisters deployed under it are uncontrolled.

Before deploying to mainnet, switch to a named identity: ``bash icp identities list # check available identities icp identity default my-identity # switch to an existing one # or: icp identity new my-identity && icp identity default my-identity ` Then verify it has funds — a new identity will need to be funded with ICP or cycles before proceeding: `bash icp token balance -n ic # check ICP balance on mainnet icp cycles balance -n ic # check cycles balance on mainnet icp identity account-id # get account ID to fund if needed ``

How It Works

Project Creation

icp new scaffolds projects from templates. Pass --subfolder, --define, and --silent for non-interactive use:

icp new my-project --subfolder rust --define project_name=my-project --silent

Available templates and options: dfinity/icp-cli-templates.

Build → Deploy → Sync

Source Code → [Build] → WASM → [Deploy] → Running Canister → [Sync] → Configured State

icp deploy runs all three phases in sequence:

  1. Build — Compile canisters to WASM (via recipes or explicit build steps)
  2. Deploy — Create canisters (if new), apply settings, install WASM
  3. Sync — Post-deployment operations via script or plugin steps (e.g., uploading assets). Asset uploading is not built into the CLI: the @dfinity/asset-canister@v2.2.1 recipe supplies a plugin sync step that uploads the dir contents. The legacy built-in type: assets step is removed in icp-cli 0.3.0 — see the asset-canister skill.

Run phases separately for more control:

icp build                     # Build only
icp deploy                    # Full pipeline (build + deploy + sync)
icp sync my-canister          # Sync only (e.g., re-upload assets)

Environments and Networks

Two implicit environments ar

…

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.