diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 27d1280e..11585681 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -125,7 +125,9 @@ These constants are defined in `crates/icp/src/prelude.rs` as `LOCAL` and `IC` a #### Identity & Canister IDs - **Identities**: Stored in `~/.config/icp/identity/` as PEM files (Secp256k1 or Ed25519) -- **Canister IDs**: Persisted in `.icp/data//canister_ids.json` within project directories +- **Canister IDs**: Persisted in `.icp/{cache,data}/mappings/.ids.json` within project directories + - Managed networks (local) use `.icp/cache/mappings/` + - Connected networks (mainnet) use `.icp/data/mappings/` Store management is in `crates/icp/src/store_id.rs`. @@ -193,8 +195,18 @@ The project includes JSON schemas for manifest validation: ### Docs generation -- The cli reference is generated in `docs/cli-reference.md`. -- Regenerate the cli reference when commands changes by running: `./scripts/generate-cli-docs.sh` +- The CLI reference is generated in `docs/reference/cli.md`. +- Regenerate the CLI reference when commands change by running: `./scripts/generate-cli-docs.sh` + +### Documentation Structure + +Documentation follows the Diátaxis framework: + +- `docs/tutorial.md` — Learning-oriented first deployment guide +- `docs/guides/` — Task-oriented how-to guides +- `docs/concepts/` — Understanding-oriented explanations +- `docs/reference/` — Information-oriented technical specifications +- `docs/migration/` — Migration guides (e.g., from dfx) ### Paths diff --git a/README.md b/README.md index 00323d15..fc2e192c 100644 --- a/README.md +++ b/README.md @@ -1,112 +1,78 @@ # icp-cli -A command-line interface for developing and deploying applications on the Internet Computer Protocol (ICP). +A command-line tool for building and deploying applications on the Internet Computer. -## Usage - -See the [command line reference](docs/cli-reference.md). - -## Installing - -For now, you have to build icp-cli locally in order to use it. - -### Prerequisites - -- **Rust**: Install Rust using [rustup](https://rustup.rs/). The project uses Rust 2024 edition. -- **mops**: Required if you want to build Motoko canisters. See [mops.one](https://cli.mops.one/). - -### Building +## Quick Start ```bash -# Build all crates in the workspace -cargo build +# Install via Homebrew (macOS) +brew install dfinity/tap/icp-cli -# Add target directory to your path -export PATH=$(pwd)/target/debug:$PATH +# Create and deploy a project +icp new my-project && cd my-project +icp network start -d +icp deploy -# Check that you can run -icp help +# List your canisters and call a method (canister name depends on your template) +icp canister list +icp canister call greet '("World")' ``` -### [Optional] Add motoko tools to the path +See the [Installation Guide](docs/guides/installation.md) for all installation methods including building from source. -You might also need the Motoko compiler if you plan on building canisters with Motoko. The best way -is to install mops, the motoko package manager, see: https://cli.mops.one/ +## For dfx Users -Reminder, when mops is installed the first time, you must initialize the toolchain with: +If you're coming from dfx (the previous Internet Computer SDK), see the **[Migration Guide](docs/migration/from-dfx.md)** for command mappings, workflow differences, and how to migrate existing projects. -```bash -mops toolchain init -``` - -### Examples +## Documentation -The `examples/` directory contains various project templates and configurations that demonstrate how to use the CLI with different project types: +- **[Tutorial](docs/tutorial.md)** — Deploy your first canister +- **[Guides](docs/guides/index.md)** — How to accomplish common tasks +- **[Concepts](docs/concepts/index.md)** — Understand how icp-cli works +- **[Reference](docs/reference/index.md)** — Complete CLI and configuration reference -- `icp-motoko/` - Motoko canister example -- `icp-rust/` - Rust canister example -- `icp-static-assets/` - Static website deployment -- `icp-multi-canister/` - Multi-canister project setup -- And many more... +## Examples -## Development +The [`examples/`](examples/) directory contains example projects to help you get started: -### Prerequisites +- `icp-motoko/` — Motoko canister +- `icp-rust/` — Rust canister +- `icp-static-assets/` — Static website +- `icp-environments/` — Multi-environment setup -- **Rust**: Install Rust using [rustup](https://rustup.rs/). The project uses Rust 2024 edition. +[View all examples →](examples/) -### Building +## Prerequisites -This is a Rust workspace with multiple crates. To build the project: +**Language-specific toolchains** (install for the languages you'll use): +- **Rust canisters** — [Rust](https://rustup.rs/) and `rustup target add wasm32-unknown-unknown` +- **Motoko canisters** — [mops](https://cli.mops.one/) and `mops toolchain init` -```bash -# Build all crates in the workspace -cargo build +## Getting Help -# Build in release mode for better performance -cargo build --release +- **[Documentation](docs/index.md)** — Guides, concepts, and reference +- **[GitHub Issues](https://github.com/dfinity/icp-cli/issues)** — Bug reports and feature requests +- **[Developer Forum](https://forum.dfinity.org/)** — Questions and discussions +- **[Discord](https://discord.internetcomputer.org)** — Real-time community chat in #dx-feedback -# Build only the CLI binary -cargo build --bin icp -``` - -The compiled binary will be available at `target/debug/icp` (or `target/release/icp` for release builds). +## Contributing -### Running Tests +Contributions are welcome! See [CONTRIBUTING.md](.github/CONTRIBUTING.md) for guidelines. ```bash -cargo test -``` - -The network launcher binary is automatically downloaded on first test run. Some tests launch local networks and require available ports. - -### Generating CLI Documentation +# Build +cargo build -The project includes automatic CLI documentation generation using `clap_markdown`. To generate comprehensive documentation for all commands: +# Test +cargo test -```bash -# Run the documentation generation script +# Generate CLI docs ./scripts/generate-cli-docs.sh -``` -This will: -- Build the CLI in release mode -- Generate complete markdown documentation at `docs/cli-reference.md` - -You can also generate documentation manually: - -```bash -# Build the CLI first -cargo build --release - -# Generate markdown documentation -./target/release/icp --markdown-help > docs/cli-reference.md +# Update the yaml file schemas +./scripts/config-schemas.sh ``` -## Contributing - -Contributions are welcome! Please see the [contribution guide](./.github/CONTRIBUTING.md) for more information. - ## License -This project is licensed under the [Apache-2.0](./LICENSE) license. +[Apache-2.0](LICENSE) diff --git a/docs/concepts/build-deploy-sync.md b/docs/concepts/build-deploy-sync.md new file mode 100644 index 00000000..55d95e70 --- /dev/null +++ b/docs/concepts/build-deploy-sync.md @@ -0,0 +1,213 @@ +# Build, Deploy, Sync + +Canisters go through three distinct phases when moving from source code to running on the Internet Computer. + +## Overview + +``` +Source Code → [Build] → WASM → [Deploy] → Running Canister → [Sync] → Configured State +``` + +Each phase has a specific purpose: + +| Phase | Purpose | Commands | +|-------|---------|----------| +| **Build** | Compile source to WASM | `icp build` or `icp deploy` | +| **Deploy** | Create canister and install WASM | `icp deploy` | +| **Sync** | Post-deployment configuration | `icp deploy` or `icp sync` | + +**Note:** `icp deploy` runs all three phases in sequence. Use individual commands when you need more control. + +## Build Phase + +The build phase transforms your source code into WebAssembly (WASM) bytecode. + +### What Happens + +1. Build steps from your configuration execute in sequence +2. Each step can run commands, copy files, or process assets +3. The final output is a `.wasm` file ready for deployment + +### Key Points + +- icp-cli **delegates** compilation to your language toolchain (Cargo for rust, mops for Motoko, etc.) +- Build output should be **reproducible** — no environment specific values should be baked in. +- The toolchain decides whether rebuilding is necessary. +- As part of the build phase you might build assets to be synchronized to the canister after the was is installed. For example, bundled web assets to serve a frontend. + +### Build Step Types + +**Script** — Run shell commands: + +```yaml +build: + steps: + - type: script + commands: + - cargo build --target wasm32-unknown-unknown --release + - cp target/wasm32-unknown-unknown/release/my_canister.wasm "$ICP_WASM_OUTPUT_PATH" +``` + +**Pre-built** — Use existing WASM: + +```yaml +build: + steps: + - type: pre-built + path: dist/canister.wasm + sha256: abc123... # Optional integrity check +``` + +**Assets** — Bundle static files: + +```yaml +build: + steps: + - type: script + commands: + - npm run build +``` + +### Environment Variables + +Scripts have access to: + +- `ICP_WASM_OUTPUT_PATH` — Where to place the final WASM +- `ICP_PROJECT_ROOT` — The project root directory + +## Deploy Phase + +The deploy phase creates or updates canisters on a network. + +### First Deployment + +When deploying a canister for the first time: + +1. An empty canister is **created** on the network +2. The canister receives a unique **canister ID** +3. Initial **cycles** are allocated +4. Canister **settings** are applied (memory, compute allocation, etc.) +5. Your WASM code is **installed** + +### Subsequent Deployments + +When the canister already exists: + +1. The existing canister is located by ID +2. New WASM code is **upgraded** (preserving stable memory) +3. Settings are updated if changed + +## Sync Phase + +The sync phase handles post-deployment operations that depend on the canister being deployed. + +### Common Use Cases + +- **Asset canisters** — Upload static files after the canister is running + +### Asset Sync + +For frontend canisters, sync uploads your built assets: + +```yaml +sync: + steps: + - type: assets + source: dist + target: / +``` + +### When Sync Runs + +- Automatically after `icp deploy` +- Manually with `icp sync` + +Run sync without redeploying: + +```bash +icp sync my-canister +``` + +## The Full Picture + +### What `icp deploy` Does + +The `icp deploy` command is a composite command that executes multiple steps in sequence: + +1. **Build** — Compile all target canisters to WASM (always runs) +2. **Create** — Create canisters on the network (only for canisters that don't exist yet) +3. **Update Canister Environment Variables** — Apply the updated Canister Environment Variables. These include variables used by bindings allowing canister interactions. +4. **Update Settings** — Apply canister settings (controllers, memory allocation, compute allocation, etc.) +5. **Install** — Install WASM code into canisters (always runs) +6. **Sync** — Run post-deployment steps like asset uploads (only if sync steps are configured) + +### Initial vs Follow-up Deployments + +**First deployment:** +- All steps run +- New canisters are created on the network +- Settings are applied +- WASM code is installed (install mode) + +**Subsequent deployments:** +- Skip the canister creation +- Settings and Environment Variables are applied if they've changed. +- WASM code is upgraded, preserving canister state + +Unlike `icp canister create` (which prints "already exists" and exits), `icp deploy` silently skips creation for existing canisters and continues with the remaining steps. + +### Install Modes + +The `--mode` flag controls how WASM is installed: + +```bash +# Auto (default) — install for new canisters, upgrade for existing +icp deploy + +# Install — only works on empty canisters +icp deploy --mode install + +# Upgrade — preserves state, runs upgrade hooks +icp deploy --mode upgrade + +# Reinstall — clears all state (use with caution) +icp deploy --mode reinstall +``` + +### Equivalent Individual Commands + +What `icp deploy` does can be broken down into: + +```bash +icp build # 1. Build +icp canister create # 2. Create (if needed) +# (canister env vars updated) # 3. Set environment variables +# (canister settings updated) # 4. Sync settings +icp canister install --mode auto # 5. Install +icp sync # 6. Sync (if configured) +``` + +### Running Phases Separately + +For more control, run phases individually: + +```bash +# Build only — compile without deploying +icp build + +# Sync only — re-upload assets without rebuilding or reinstalling +icp sync +``` + +**When to run separately:** + +- `icp build` — Verify compilation succeeds before deploying +- `icp sync` — Update assets without redeploying code (faster iteration for frontends) + +**Note:** `icp deploy` always builds first. There's no way to skip the build phase during deploy. The build phase relies on the underlying toolchain (Cargo, moc, etc.) handling incremental compilation. + +## Next Steps + +- [Local Development](../guides/local-development.md) — Apply this in practice + +[Browse all documentation →](../index.md) diff --git a/docs/concepts/environments.md b/docs/concepts/environments.md new file mode 100644 index 00000000..77b4f4b8 --- /dev/null +++ b/docs/concepts/environments.md @@ -0,0 +1,189 @@ +# Environments and Networks + +Understanding the relationship between networks and environments is key to effective deployment management. + +## Networks + +A **network** is an ICP network endpoint that icp-cli can connect to. + +### Network Types + +**Managed Networks** + +icp-cli controls the lifecycle — starting, stopping, and resetting: + +```yaml +networks: + - name: local + mode: managed + gateway: + host: 127.0.0.1 + port: 8000 +``` +Managed networks can run natively on your machine or inside a docker container. + +Use managed networks for local development and testing. + +**Connected Networks** + +External networks that icp-cli connects to but doesn't control: + +```yaml +networks: + - name: testnet + mode: connected + url: https://testnet.ic0.app +``` + +Use connected networks for shared testnets and production. + +### Implicit Networks + +Two networks are always available: + +| Network | Type | Description | +|---------|------|-------------| +| `local` | Managed | Local development network on `localhost:8000` | +| `ic` | Connected | The Internet Computer mainnet at `https://icp-api.io` | + +The `local` network can be overridden in your `icp.yaml`. The `ic` network is **protected** and cannot be overridden to prevent accidental production deployment with incorrect settings. + +### Overriding Local + +Customize your local development network: + +```yaml +networks: + - name: local + mode: managed + gateway: + port: 9999 # Different port +``` + +Or connect to an existing network instead of managing one: + +```yaml +networks: + - name: local + mode: connected + url: http://192.168.1.100:8000 + root-key: +``` + +## Environments + +An **environment** is a named deployment target that combines: + +- A **network** to deploy to +- A set of **canisters** to include +- **Settings** for those canisters + +### Why Environments? + +Without environments, you'd need to: +- Remember which network to deploy to +- Manually specify settings for each deployment +- Track canister IDs separately + +Environments encapsulate all of this. + +### Implicit Environments + +Two environments are always available: + +| Environment | Network | Canisters | +|-------------|---------|-----------| +| `local` | `local` | All canisters | +| `ic` | `ic` | All canisters | + +### Defining Environments + +```yaml +environments: + - name: staging + network: ic + canisters: [frontend, backend] + settings: + backend: + compute_allocation: 5 + + - name: production + network: ic + canisters: [frontend, backend] + settings: + backend: + compute_allocation: 20 + freezing_threshold: 7776000 +``` + +### Environment-Specific Settings + +Settings cascade with environment overrides taking precedence: + +```yaml +canisters: + - name: backend + settings: + compute_allocation: 1 # Default + +environments: + - name: staging + network: ic + canisters: [backend] + + - name: production + network: ic + canisters: [backend] + settings: + backend: + compute_allocation: 20 # Override for production +``` + +### Using Environments + +```bash +# Local development (default) +icp deploy + +# Explicit local +icp deploy --environment local + +# Custom environment +icp deploy --e staging +``` + +## Networks vs Environments + +| Aspect | Network | Environment | +|--------|---------|-------------| +| **Purpose** | Where to connect | What to deploy and how | +| **Contains** | URL, connection details | Network reference, canisters, settings | +| **Examples** | `local`, `ic`, `testnet` | `local`, `ic`, `staging`, `production` | + +A common pattern: + +``` +Networks: local, ic +Environments: local, staging, production + ↓ ↓ ↓ + local ic ic +``` + +Multiple environments can target the same network with different settings. + +## Canister IDs per Environment + +Each environment maintains separate canister IDs. The storage location depends on network type: + +- **Managed networks** (local): `.icp/cache/mappings/.ids.json` +- **Connected networks** (IC mainnet): `.icp/data/mappings/.ids.json` + +**IMPORTANT** Creating canisters on the IC mainnet is like buying real-estate so you should make sure +not to lose the canister IDs. It is common practice to check in the contents of `.icp/data` in +source control so as not to lose them. + +## Next Steps + +- [Managing Environments](../guides/managing-environments.md) — Apply this in practice + +[Browse all documentation →](../index.md) diff --git a/docs/concepts/index.md b/docs/concepts/index.md new file mode 100644 index 00000000..fb7f29d3 --- /dev/null +++ b/docs/concepts/index.md @@ -0,0 +1,21 @@ +# Concepts + +Understanding how icp-cli organizes and manages your project. + +## Core Concepts + +- [Project Model](project-model.md) — How icp-cli discovers and consolidates configuration +- [Build, Deploy, Sync](build-deploy-sync.md) — The three phases of the deployment lifecycle +- [Environments and Networks](environments.md) — Deployment targets and how they relate +- [Recipes](recipes.md) — Templated, reusable build configurations + +## Quick Reference + +| Term | Definition | +|------|------------| +| **Project** | A directory containing `icp.yaml` and your canister source code | +| **Canister** | A unit of deployment on the Internet Computer — your compiled WASM plus settings | +| **Network** | An ICP network endpoint — local (managed by icp-cli) or remote (mainnet, testnet) | +| **Environment** | A named deployment target combining a network with canister settings | +| **Recipe** | A Handlebars template that generates build and sync configuration | +| **Principal** | A public identifier for an identity or canister on the Internet Computer | diff --git a/docs/concepts/project-model.md b/docs/concepts/project-model.md new file mode 100644 index 00000000..219e6daa --- /dev/null +++ b/docs/concepts/project-model.md @@ -0,0 +1,228 @@ +# Project Model + +This document explains how icp-cli discovers, loads, and consolidates your project configuration. + +## Project Structure + +An icp-cli project is any directory containing an `icp.yaml` file. This file is the root of your project configuration. + +The project layout is flexible but a typical layout will look like the one below. Notice that some of the directories +and configuration files are marked as optional: This is because the configuration can be split across multiple files +or inlined inside `icp.yaml` + +``` +my-project/ +├── icp.yaml # Project configuration +├── networks/ # [Optional] network manifests +│ ├── testnet1.yaml +│ └── testnet2.yaml +├── environments/ # [Optional] environment manifests +│ ├── dev.yaml +│ ├── production.yaml +│ └── staging.yaml +└── src/ # Canister source code + └── canisters/ + ├── frontend/ + │ └── canister.yaml # [Optional] canister manifest + └── backend/ + └── canister.yaml # [Optional] canister manifest +``` + +## The icp.yaml File + +The `icp.yaml` file defines: + +- **Canisters** — What to build and deploy +- **Networks** — Where to deploy (optional, defaults provided) +- **Environments** — Named deployment configurations (optional, defaults provided) + +Minimal example: + +```yaml +canisters: + - name: hello + build: + steps: + - type: script + commands: + - cargo build --target wasm32-unknown-unknown --release + - cp target/wasm32-unknown-unknown/release/hello.wasm "$ICP_WASM_OUTPUT_PATH" +``` + +## Network Discovery + +Networks can be defined in three ways: + +### Implicit networks + +There are two implicit networks defined: +- `local` - is a local managed network +- `ic` - is the IC mainnet (connected network) + +Their configuration is equivalent to: + +```yaml +networks: + - name: ic + configuration: + mode: connected + url: https://icp-api.io + - name: local + configuration: + mode: managed + gateway: + host: localhost + port: 8000 +``` + +### Inline Definition + +Define networks directly in `icp.yaml` + +```yaml +networks: + - name: testnet + configuration: + mode: connected + url: https://my-icp-testnet.io + root-key: +``` + +### External Files + +Reference separate YAML files + +```yaml +networks: + - networks/testnet1.yaml + - networks/testnet2.yaml + +``` + +## Environment Discovery + +Environments can be defined in three ways: + +### Implicit Environments + +There are two implicit environments: +- `local` - uses the local managed network +- `ic` - uses the IC mainnet + +They are defined like this: + +```yaml +environments: + - name: local + network: local + - name: ic + network: ic +``` + +### Inline Definition + +Define environments directly in `icp.yaml` + +```yaml +environments: + - name: my-staging-env + network: mainnet + - name: my-production-env + network: mainnet + +``` + +### External Files + +Reference separate YAML files + +```yaml +environments: + - env/my-staging-env.yaml + - env/my-production-env.yaml + +``` + +## Canister Discovery + +Canisters can be defined in three ways: + +### Inline Definition + +Define canisters directly in `icp.yaml`: + +```yaml +canisters: + - name: my-canister + build: + steps: + - type: script + commands: + - echo "Building..." +``` + +### External Files + +Reference separate YAML files: + +```yaml +canisters: + - frontend # look for frontend/canister.yaml + - backend # look for backend/canister.yaml +``` + +### Glob Patterns + +Discover canisters automatically: + +```yaml +canisters: + - canisters/* # find all `canister.yaml` files in canisters/** +``` + +## Configuration Consolidation + +icp-cli consolidates configuration from multiple sources into a single effective configuration. The order of precedence (highest to lowest): + +1. **Environment-specific settings** — Override everything for that environment +2. **Canister-level settings** — Default settings for a canister +3. **Recipe-generated configuration** — Expanded from recipe templates +4. **Implicit defaults** — Built-in networks and environments + +View the effective configuration: + +```bash +# outputs the effect project configuration in yaml +icp project show + +# You can use yq to view the effective settings of a canister +# in a particular environment. Here we're looking at the settings +# in the 'local' enviroment +icp project show | yq -r ".environments.local" + +``` + +## Canister IDs + +When you deploy, icp-cli records canister IDs in mapping files. The location depends on the network type: + +- **Managed networks** (eg: local): `.icp/cache/mappings/.ids.json` +- **Connected networks** (eg: mainnet): `.icp/data/mappings/.ids.json` + +Each environment maintains separate canister IDs, so your local deployment and mainnet deployment have different IDs. + +The mapping file for managed networks is ephemeral, meaning that it will be removed when the network is stopped. + +## Project Root Detection + +icp-cli looks for `icp.yaml` in the current directory and parent directories. You can override this: + +```bash +icp deploy --project-root-override /path/to/project +``` + +## Next Steps + +- [Build, Deploy, Sync](build-deploy-sync.md) — The deployment lifecycle + +[Browse all documentation →](../index.md) diff --git a/docs/concepts/recipes.md b/docs/concepts/recipes.md new file mode 100644 index 00000000..f76918a0 --- /dev/null +++ b/docs/concepts/recipes.md @@ -0,0 +1,148 @@ +# Recipes + +Recipes are templated build configurations that generate build and sync steps. They reduce boilerplate and encode best practices for common patterns. + +## How Recipes Work + +A recipe is a [Handlebars](https://handlebarsjs.com/) template that takes configuration parameters and expands into full canister configuration. + +``` +Recipe Template + Configuration → Expanded Build/Sync Steps +``` + +### Example + +Given this recipe usage: + +```yaml +canisters: + - name: backend + recipe: + type: "@dfinity/rust" + configuration: + package: my-backend +``` + +The recipe expands to something like: + +```yaml +canisters: + - name: backend + build: + steps: + - type: script + commands: + - cargo build --package my-backend --target wasm32-unknown-unknown --release + - cp target/wasm32-unknown-unknown/release/my_backend.wasm "$ICP_WASM_OUTPUT_PATH" +``` + +## Recipe Sources + +Recipes can come from three sources: + +### Registry (Recommended) + +Official recipes from the DFINITY registry: + +```yaml +recipe: + type: "@dfinity/rust" + configuration: + package: my-crate +``` + +Version pinning: + +```yaml +recipe: + type: "@dfinity/rust@v1.0.0" +``` + +The `@dfinity` prefix resolves to [github.com/dfinity/icp-cli-recipes](https://github.com/dfinity/icp-cli-recipes). + +### Local Files + +Project-specific recipes: + +```yaml +recipe: + type: ./recipes/my-template.hb.yaml + configuration: + param: value +``` + +### Remote URLs + +Recipes hosted anywhere: + +```yaml +recipe: + type: https://example.com/recipes/custom.hb.yaml + sha256: 17a05e36278cd04c7ae6d3d3226c136267b9df7525a0657521405e22ec96be7a + configuration: + param: value +``` + +Always include `sha256` for remote recipes. + +## Available Official Recipes + +| Recipe | Purpose | +|--------|---------| +| `@dfinity/rust` | Rust canisters with Cargo | +| `@dfinity/motoko` | Motoko canisters | +| `@dfinity/asset-canister` | Asset canisters for static files | +| `@dfinity/prebuilt` | Pre-compiled WASM files | + +## Recipe Template Syntax + +Recipes use Handlebars templating: + +```yaml +# recipes/example.hb.yaml +build: + steps: + - type: script + commands: + {{#if optimize}} + - cargo build --release + {{else}} + - cargo build + {{/if}} + - cp target/{{configuration.package}}.wasm "$ICP_WASM_OUTPUT_PATH" + +``` + +### Template Variables + +icp-cli will essentially render the handlebar template with all the parameters passed +in the configuration section of the recipe. + +## Viewing Expanded Configuration + +See what recipes expand to: + +```bash +icp project show +``` + +This displays the effective configuration after all recipes are rendered. + +## When to Use Recipes + +**Use recipes when:** +- Building standard canister types (Rust, Motoko, Asset Canister) +- Sharing configurations across multiple canisters +- Encoding team-specific build conventions + +**Use direct build steps when:** +- Your build process is unique +- You need fine-grained control +- The overhead of a recipe isn't justified + +## Next Steps + +- [Using Recipes](../guides/using-recipes.md) — Apply recipes in your projects +- [Creating Recipes](../guides/creating-recipes.md) — Build custom recipes + +[Browse all documentation →](../index.md) diff --git a/docs/getting-started.md b/docs/getting-started.md deleted file mode 100644 index bdaab698..00000000 --- a/docs/getting-started.md +++ /dev/null @@ -1,282 +0,0 @@ -# Getting Started with ICP CLI - -This guide will walk you through setting up ICP CLI and deploying your first canister to the Internet Computer. - -## What is ICP CLI? - -ICP CLI is a modern command-line tool for developing and deploying applications on the Internet Computer Protocol (ICP). It provides a streamlined workflow for building, testing, and deploying canisters with support for multiple programming languages and deployment environments. - -## Prerequisites - -Before you begin, ensure you have the following installed: - -### Required -- **Rust**: Install using [rustup](https://rustup.rs/) - -### Language-Specific Requirements -- **For Rust canisters**: `rustup target add wasm32-unknown-unknown` -- **For Motoko canisters**: Motoko compiler (`moc`) - included with [dfx](https://internetcomputer.org/docs/building-apps/getting-started/install) - -## Installation - -Currently, you need to build ICP CLI from source: - -```bash -# Clone the repository (if not already done) -git clone -cd icp-cli - -# Build the project -cargo build --release - -# Add to PATH for easier access -export PATH=$(pwd)/target/release:$PATH - -# Verify installation -icp help -``` - -### Setting Up Dependencies - -If you want to use Motoko, install the Motoko package manager: - -```bash -# Make sure you have installed mops, see https://cli.mops.one/ -# and have initialized the toolchain -mops toolchain init -``` - -## Your First Canister - -Let's create and deploy a simple "Hello World" canister. - -### 1. Create a New Project - -Choose from one of the examples to get started quickly: - -```bash -# Create a project from a template -# by default icp-cli will use templates in https://github.com/dfinity/icp-cli-templates -# -# -icp new my-project - -# -# Select the type of project you want to start with -# - -cd my-project -``` - -### 2. Understand the Project Structure - -A typical project contains: - -- `icp.yaml` - Project configuration file -- `src/` - Source code directory -- `README.md` - Project-specific instructions - -Let's look at the `icp.yaml` file: - -```yaml -canisters: - - name: my-canister - build: - steps: - - type: script - commands: - # Build commands specific to your language -``` - -Note that the configuration can be split across different files. To see the effective -project configuration, you can run: - -```bash -icp project show -``` - -### 3. Start a Local Network - -Start the local Internet Computer network: - -```bash -icp network start -d -``` - -This starts a local replica where you can deploy and test your canisters. - -### 4. Build Your Canister - -Build your project: - -```bash -icp build my-canister -``` - -This command: -- Executes the build steps defined in `icp.yaml` -- Compiles your source code to WebAssembly (WASM) -- Prepares the canister for deployment - -### 5. Deploy to Local Network - -Deploy your canister to the local network: - -```bash -icp deploy -``` - -This command: -- Creates a new canister ID (if first deployment) -- Installs the WASM code to the canister -- Makes your canister available for interaction - -### 6. Interact with Your Canister - -Call methods on your deployed canister: - -```bash -# For the example canisters, try: -icp canister call my-canister greet '("World")' -``` - -You should see a response like `("Hello, World!")`. - -## Common Workflows - -### Development Cycle -```bash -# 1. Make changes to your source code -# 2. Build the updated canister -icp build my-canister - -# 3. Redeploy (upgrade) the canister -icp deploy - -# 4. Test your changes -icp canister call my-canister method_name '(args)' -``` - -### Working with Multiple Canisters -```bash -# Build a specific canister -icp build canister1 - -# Deploy specific canisters -icp deploy canister1 - -# List all canisters in project -icp canister list -``` - -## Networks and Environments - -A *network* is a url through which you can reach an ICP network. This could be "ic", -the official ICP network reachable at https://icp-api.io, a local or remote network started -for test or development purposes. - -An *environment* represents a set of canisters to deploy to a network. For example you could -have: -- A local development environment pointing using your local network -- A staging environment deployed to the IC mainnet -- A production envrionment deployed to the IC mainnet - -For example: - -```yaml -environments: - - name: staging - network: ic - - name: prod - network: ic -``` -There is always an implicit "local" environment using the "local" network which is the default -and that cannot be overriden. - -To deploy to a specific environment use: - -```bash - -# Deploy to a custom environment -icp deploy --environment staging -``` - -## Project Configuration Basics - -The `icp.yaml` file is the heart of your project configuration. Here are the key concepts: - -### Single Canister Project -```yaml -canisters: - - name: my-canister - build: - steps: - - type: script - commands: - - cargo build --target wasm32-unknown-unknown --release -``` - -### Multi-Canister Project -```yaml -canisters: - - canisters/* # Glob pattern to find canister configs -``` - -### Using Recipes - -Recipes allow templating build instructions and sharing them across projects. -The DFINITY foundation maintains a set of recipes at https://github.com/dfinity/icp-cli-recipes. -You can also host your own. - -```yaml -canisters: - - name: my-canister - recipe: - type: rust # Built-in recipe for Rust canisters - configuration: - package: my-canister -``` - -## Next Steps - -Now that you have your first canister running, explore: - -1. **[Project Configuration](project-configuration.md)** - Deep dive into `icp.yaml` options -2. **[CLI Reference](cli-reference.md)** - Complete command documentation -3. **[Examples](../examples/)** - More complex project templates -4. **[Advanced Workflows](workflows.md)** - Multi-environment deployments, CI/CD - -## Troubleshooting - -### Common Issues - -**Build fails with "command not found"** -- Ensure all required tools are installed and in PATH -- Check language-specific prerequisites - -**Network connection fails** -- Verify `icp network start` is running in another terminal -- The network launcher is automatically downloaded on first use. If you experience issues, you can manually set `ICP_CLI_NETWORK_LAUNCHER_PATH` to a specific launcher binary for debugging - -**Canister deployment fails** -- Verify that the local network is healthy: `icp network ping` -- Check canister build succeeded: `icp build ` - -### Getting Help - -- Use `icp help` for command overview -- Use `icp --help` for specific command help -- Check the [examples](../examples/) directory for reference implementations - -## What's Different from dfx? - -If you're familiar with dfx, here are the key differences: - -- **Configuration**: Project configuration is in `icp.yaml` vs `dfx.json`. -- **Environment**: A project is deployed to an "environment" not a network. An environment -is a logical name that points to a network (could be the IC mainnet or your local network). -- **Recipe system**: Reusable build templates you can share with your team or the community. -- **Consistent with mainnet**: Aims to make interacting with the local network the same as interacting -with the IC mainnet. - -Ready to build more complex applications? Check out our [examples](../examples/) or dive into [project configuration](project-configuration.md)! diff --git a/docs/guides/creating-recipes.md b/docs/guides/creating-recipes.md new file mode 100644 index 00000000..03e9251d --- /dev/null +++ b/docs/guides/creating-recipes.md @@ -0,0 +1,228 @@ +# Creating Recipes + +Recipes are reusable build templates that you can create to encode your team's build conventions or share them with the community. + +## Recipe File Structure + +A recipe is a [handlebars](https://handlebarsjs.com) template that renders to yaml and contains the `build` and `sync` steps +of a canister configuration. + +``` +{{! # recipes/my-recipe.hbs }} +build: + steps: + - type: script + commands: + - echo "Building {{ name }}..." + +{{! # optional sync step }} +sync: + steps: + - type: script + commands: + - echo "Syncing {{ name }}..." +``` + +## Basic Recipe Example + +A simple recipe for Rust builds: + +``` +{{! file: ./recipes/rust-example.hbs }} +{{! A recipe for building a rust canister }} +{{! `package: string` The package to build }} +{{! `shrink: boolean` Optimizes the wasm with ic-wasm }} + +build: + steps: + - type: script + commands: + - cargo build --package {{ package }} --target wasm32-unknown-unknown --release + - mv target/wasm32-unknown-unknown/release/{{ replace "-" "_" package }}.wasm "$ICP_WASM_OUTPUT_PATH" + + - type: script + commands: + - command -v ic-wasm >/dev/null 2>&1 || { echo >&2 'ic-wasm not found. To install ic-wasm, see https://github.com/dfinity/ic-wasm \n'; exit 1; } + - ic-wasm "$ICP_WASM_OUTPUT_PATH" -o "${ICP_WASM_OUTPUT_PATH}" metadata "cargo:version" -d "$(cargo --version)" --keep-name-section + - ic-wasm "$ICP_WASM_OUTPUT_PATH" -o "${ICP_WASM_OUTPUT_PATH}" metadata "template:type" -d "rust" --keep-name-section + {{#if shrink}} + - ic-wasm "$ICP_WASM_OUTPUT_PATH" -o "${ICP_WASM_OUTPUT_PATH}" shrink --keep-name-section + {{/if}} +``` + +Usage: + +```yaml +# file: icp.yaml +canisters: + - name: backend + recipe: + type: ./recipes/rust-example.hbs + configuration: + package: my-backend-crate + shrink: true +``` + +## Template Syntax + +Recipes use [Handlebars](https://handlebarsjs.com/) templating: + +### Variables + +Access configuration parameters passed in the `configuration` section of the recipe. + +``` +build: + steps: + - type: script + commands: + - cargo build --package {{configuration.package}} +``` + +### Conditionals + +Use `{{#if}}` for optional configuration: + +``` +build: + steps: + - type: script + commands: + {{#if shrink}} + - cargo build --release --target wasm32-unknown-unknown + - ic-wasm target/wasm32-unknown-unknown/release/{{configuration.package}}.wasm -o "$ICP_WASM_OUTPUT_PATH" shrink + {{else}} + - cargo build --target wasm32-unknown-unknown + - cp target/wasm32-unknown-unknown/debug/{{configuration.package}}.wasm "$ICP_WASM_OUTPUT_PATH" + {{/if}} +``` + +### Loops + +Use `{{#each}}` for dynamic lists: + +``` +{{! file: ./recipes/rust-example-metadata.hbs }} +{{! A recipe for building a rust canister }} +{{! `package: string` The package to build }} +{{! `metadata: [name: string, value: string]`: An array of name/value pairs that get injected into the wasm metadata section }} + +build: + steps: + - type: script + commands: + - cargo build --package {{ package }} --target wasm32-unknown-unknown --release + - mv target/wasm32-unknown-unknown/release/{{ replace "-" "_" package }}.wasm "$ICP_WASM_OUTPUT_PATH" + + - type: script + commands: + - command -v ic-wasm >/dev/null 2>&1 || { echo >&2 'ic-wasm not found. To install ic-wasm, see https://github.com/dfinity/ic-wasm \n'; exit 1; } + {{#if metadata}} + {{#each metadata}} + - ic-wasm "$ICP_WASM_OUTPUT_PATH" -o "${ICP_WASM_OUTPUT_PATH}" metadata "{{ name }}" -d "{{ value }}" --keep-name-section + {{/each}} + {{/if}} +``` + +```yaml +# file: icp.yaml +canisters: + - name: backend + recipe: + type: ./recipes/rust-example-metadata.hbs + configuration: + package: my-backend-crate + metadata: + - name: "crate:version" + value: "1.0.0" + - name: "build:profile" + value: "release" +``` + +### Default Values + +Use `{{#if}}` with `{{else}}` for defaults, refer to the examples above. + +## Testing Recipes + +Test your recipe by viewing the expanded configuration: + +```bash +icp project show +``` + +This shows exactly what your recipe produces after template expansion. + +Verify it works end-to-end: + +```bash +icp build +icp deploy +``` + +## Sharing Recipes + +### Within a project + +Store recipes in your project's `recipes/` directory and reference with relative paths: + +```yaml +# file: icp.yaml +canisters: + - name: canister1 + recipe: + type: ./recipes/my-recipe.hbs + configuration: + package: my-crate1 + - name: canister2 + recipe: + type: ./recipes/my-recipe.hbs + configuration: + package: my-other-crate +``` + +### Across Projects + +Host on a web server or GitHub and reference with URL and sha256 hash: + +```yaml +recipe: + type: https://example.com/recipes/my-recipe.hb.yaml + sha256: + configuration: + name: my-canister +``` + +Generate the hash: + +```bash +sha256sum recipes/my-recipe.hb.yaml +``` + +### Publishing to the Registry + +To contribute recipes to the official registry at [github.com/dfinity/icp-cli-recipes](https://github.com/dfinity/icp-cli-recipes): + +1. Fork the repository +2. Add your recipe following the contribution guidelines +3. Submit a pull request + +## Recipe Examples + +For examples of recipes, you can check out [github.com/dfinity/icp-cli-recipes](https://github.com/dfinity/icp-cli-recipes). + + +## Best Practices + +- **Keep recipes focused** — One recipe per build pattern +- **Document configuration options** — Include comments or a README +- **Provide sensible defaults** — Use conditionals to make options optional +- **Test thoroughly** — Verify recipes work across different projects +- **Version carefully** — Use semantic versioning for published recipes + +## Next Steps + +- [Using Recipes](using-recipes.md) — Apply recipes in your projects +- [Recipes Concept](../concepts/recipes.md) — Understand how recipes work + +[Browse all documentation →](../index.md) diff --git a/docs/guides/creating-templates.md b/docs/guides/creating-templates.md new file mode 100644 index 00000000..1d38a910 --- /dev/null +++ b/docs/guides/creating-templates.md @@ -0,0 +1,280 @@ +# Creating Project Templates + +Project templates let users scaffold new ICP projects with `icp new`. This guide covers creating custom templates for your team or the community. + +## Overview + +icp-cli uses [cargo-generate](https://cargo-generate.github.io/cargo-generate/) for project templating. Templates are folders or git repositories repositories containing: + +- Project files with placeholder variables +- A `cargo-generate.toml` configuration file + +## Quick Start + +### Minimal Template + +Create a basic template: + +``` +my-template/ +├── cargo-generate.toml +├── icp.yaml +├── {{project-name}}.did +└── src/ + └── main.mo +``` + +**cargo-generate.toml:** + +```toml +[template] +name = "My ICP Template" +description = "A simple ICP project template" +``` + +**icp.yaml:** + +```yaml +canisters: + - name: {{project-name}} + recipe: + type: "@dfinity/motoko" + configuration: + entry: src/main.mo +``` + +Filenames with handlebar placeholders like `{{project-name}}.did` will be renamed with value. + +### Using Your Template + +```bash +# From local directory +icp new my-project --path /path/to/my-template + +# From Git repository +icp new my-project --git https://github.com/user/my-template +``` + +## Template Variables + +### Built-in Variables + +cargo-generate provides these variables automatically: + +| Variable | Description | +|----------|-------------| +| `{{project-name}}` | Project name (kebab-case) | +| `{{crate_name}}` | Project name (snake_case) | +| `{{authors}}` | Git user name | + +### Custom Variables + +Define custom variables in `cargo-generate.toml`: + +```toml +[template] +name = "My Template" + +[placeholders] +include_frontend = { type = "bool", prompt = "Include frontend?", default = true } +``` + +Use them in templates: + +```yaml +# icp.yaml +canisters: + + # ... snip snip for brevity ... + + {{#if include_frontend}} + - name: {{project-name}}-frontend + recipe: + type: "@dfinity/assets" + configuration: + source: dist + {{/if}} + +``` + +## Template Structure + +### Recommended Layout + +``` +my-template/ +├── cargo-generate.toml # Template configuration +├── icp.yaml # Project manifest +├── README.md # Project readme (templated) +├── src/ +│ ├── backend/ +│ │ └── main.mo # Backend source +│ └── frontend/ # Frontend (if applicable) +│ └── index.html +└── .gitignore +``` + +### Configuration File + +A complete `cargo-generate.toml`: + +```toml +[template] +name = "Full Stack ICP App" +description = "A complete ICP application with backend and frontend" +# Exclude files from the generated project +exclude = [ + ".git", + "target", + ".icp" +] + +[placeholders] +backend_language = { type = "string", prompt = "Backend language?", choices = ["motoko", "rust"], default = "motoko" } +include_frontend = { type = "bool", prompt = "Include frontend?", default = true } +frontend_framework = { type = "string", prompt = "Frontend framework?", choices = ["vanilla", "react", "svelte"], default = "vanilla" } + +# Conditional files based on selections +[conditional] +# Include Cargo.toml only for Rust projects +"Cargo.toml" = { condition = "backend_language == 'rust'" } +"src/backend/lib.rs" = { condition = "backend_language == 'rust'" } +"src/backend/main.mo" = { condition = "backend_language == 'motoko'" } +``` + +## Advanced Features + +### Conditional Content + +Use Handlebars conditionals in any file: + +```yaml +# icp.yaml +canisters: + - name: {{project-name}} + {{#if (eq backend_language "rust")}} + recipe: + type: "@dfinity/rust" + configuration: + package: {{crate_name}} + {{else}} + recipe: + type: "@dfinity/motoko" + configuration: + entry: src/backend/main.mo + {{/if}} +``` + +### Conditional Files + +Include files based on user choices: + +```toml +# cargo-generate.toml +[conditional] +"src/frontend/" = { condition = "include_frontend" } +"package.json" = { condition = "include_frontend" } +``` + +### Post-Generation Hooks + +Run commands after generation: + +```toml +[hooks] +post = ["npm install"] +``` + +Note: Hooks require the user to have the necessary tools installed. + +### Subfolders for Multiple Templates + +Organize multiple templates in one repository: + +``` +icp-templates/ +├── motoko-basic/ +│ └── cargo-generate.toml +├── rust-basic/ +│ └── cargo-generate.toml +└── full-stack/ + └── cargo-generate.toml +``` + +Use with `--subfolder`: + +```bash +icp new my-project --git https://github.com/org/icp-templates --subfolder motoko-basic +``` + +## Example Templates + +The default templates in [github.com/dfinity/icp-cli-templates](https://github.com/dfinity/icp-cli-templates) serve as good +examples to follow. + +To use more advanced features of cargo-generate, it is recommended you check out the book [https://cargo-generate.github.io/cargo-generate/](https://cargo-generate.github.io/cargo-generate/). + +## Testing Templates + +### Local Testing + +Test without publishing: + +```bash +# Test from local directory +icp new test-project --path ./my-template + +# Verify the generated project +cd test-project +icp network start -d +icp deploy +``` + +### Validation Checklist + +Before publishing, verify: + +- [ ] `icp new` completes without errors +- [ ] Generated project builds: `icp build` +- [ ] Generated project deploys to the local network: `icp deploy` +- [ ] Variables are substituted correctly +- [ ] Conditional content works as expected +- [ ] README is helpful and accurate + +## Publishing Templates + +### GitHub Repository + +1. Push your template to GitHub +2. Users can reference it directly: + +```bash +icp new my-project --git https://github.com/username/my-template +``` + +### With Tags/Branches + +Pin to specific versions: + +```bash +# Use a tag +icp new my-project --git https://github.com/user/template --tag v1.0.0 + +# Use a branch +icp new my-project --git https://github.com/user/template --branch stable +``` + +### Official Templates + +The default templates are in [github.com/dfinity/icp-cli-templates](https://github.com/dfinity/icp-cli-templates). To contribute: + +1. Fork the repository +2. Add your template as a subfolder +3. Submit a pull request + +## Next Steps + +- [Tutorial](../tutorial.md) — Use templates to create projects +- [Creating Recipes](creating-recipes.md) — Create reusable build configurations + +[Browse all documentation →](../index.md) diff --git a/docs/guides/deploying-to-mainnet.md b/docs/guides/deploying-to-mainnet.md new file mode 100644 index 00000000..9d446546 --- /dev/null +++ b/docs/guides/deploying-to-mainnet.md @@ -0,0 +1,181 @@ +# Deploying to IC Mainnet + +This guide walks through deploying your canisters to the Internet Computer mainnet. + +## Prerequisites + +Before deploying to mainnet, ensure you have: + +1. **A working project** — Test locally first with `icp deploy` on your local network +2. **An identity** — See [Managing Identities](managing-identities.md) +3. **Cycles** — Canisters require cycles to run on mainnet + +## Setting Up an Identity + +If you haven't already, create an identity: + +```bash +icp identity new mainnet-deployer +``` + +Set it as default: + +```bash +icp identity default mainnet-deployer +``` + +View your principal: + +```bash +icp identity principal +``` + +## Acquiring Cycles + +Canisters need cycles to operate on mainnet. You'll need cycles before deploying. + +**Quick start:** + +```bash +# Check your cycles balance +icp cycles balance -e ic + +# Convert ICP to cycles (if you have ICP) +icp cycles mint --icp 1 -e ic +``` + +**How many cycles do you need?** +- Creating a canister: ~100B cycles (0.1T) +- Simple backend: 1-5T cycles lasts weeks to months +- Start with 1-2T cycles and top up as needed + +For detailed information on acquiring ICP, converting to cycles, and managing balances, see [Tokens and Cycles](tokens-and-cycles.md). + +## Deploying + +To deploy to the IC mainnet, use the implicit `ic` environment with the `--environment ic` flag or the `-e ic` shorthand: + +```bash +icp deploy --environment ic +``` + +This will: +1. Build your canisters +2. Create canisters on mainnet (if first deployment) +3. Install your WASM code +4. Run any sync steps (e.g., asset uploads) + +### Deploying Specific Canisters + +Deploy only certain canisters: + +```bash +icp deploy frontend --environment ic +``` + +### Using Environments + +You can configure multiple environments pointing to the IC mainnet in `icp.yaml`: + +```yaml + +environments: + - name: prod + network: ic # ic is an implicit network + - name: staging + network: ic +``` +This allows you to deploy independent sets of canisters for each environment: + +```bash +icp deploy -e staging +icp deploy --environment prod +``` + +See [Managing Environments](managing-environments.md) for setup details. + +## Verifying Deployment + +List canisters configured in this environment: + +```bash + +# List the canisters in an environment +icp canister list -e myenv + +# Check canister status: +icp canister status my-canister -e myenv + +# Call a method to verify it's working: +icp canister call my-canister greet '("World")' -e myenv +``` + +## Updating Deployed Canisters + +After making changes, redeploy: + +```bash +icp deploy --environment prod +``` + +This rebuilds and upgrades your existing canisters, preserving their state. + +## Managing Canister Settings + +View current settings: + +```bash +icp canister settings show my-canister -e prod +``` + +Update settings: + +```bash +icp canister settings update my-canister --freezing-threshold 2592000 -e prod +``` + +## Topping Up Cycles + +Monitor canister cycles and top up when needed: + +```bash +# Check canister cycles balance +icp canister status my-canister -e prod + +# Top up with 1 trillion cycles +icp canister top-up my-canister --amount 1000000000000 -e prod +``` + +See [Tokens and Cycles](tokens-and-cycles.md) for more on managing cycles. + +## Troubleshooting + +**"Insufficient cycles"** + +Your canister needs more cycles. Top up using: + +```bash +icp canister top-up my-canister --amount 1000000000000 -e prod +``` + +**"Not a controller"** + +You're not authorized to modify this canister. Verify you're using the correct identity: + +```bash +icp identity principal +icp identity list +``` + +If needed, switch to the correct identity: + +```bash +icp identity default +``` + +## Next Steps + +- [Tokens and Cycles](tokens-and-cycles.md) — Managing ICP and cycles in detail +- [Managing Environments](managing-environments.md) — Set up staging and production + +[Browse all documentation →](../index.md) diff --git a/docs/guides/index.md b/docs/guides/index.md new file mode 100644 index 00000000..6cd460a3 --- /dev/null +++ b/docs/guides/index.md @@ -0,0 +1,27 @@ +# Guides + +Step-by-step instructions for common tasks. Each guide assumes you've completed the [Tutorial](../tutorial.md). + +## Getting Started + +- [Installation](installation.md) — Install icp-cli on your system + +## Development + +- [Local Development](local-development.md) — The edit-build-deploy cycle for day-to-day work + +## Deployment + +- [Deploying to Mainnet](deploying-to-mainnet.md) — Go live on the Internet Computer +- [Managing Environments](managing-environments.md) — Configure dev, staging, and production +- [Tokens and Cycles](tokens-and-cycles.md) — Manage ICP tokens and cycles + +## Configuration + +- [Using Recipes](using-recipes.md) — Reusable build templates for common patterns +- [Managing Identities](managing-identities.md) — Keys, principals, and authentication + +## Advanced + +- [Creating Recipes](creating-recipes.md) — Build custom recipe templates +- [Creating Templates](creating-templates.md) — Author project templates for `icp new` diff --git a/docs/guides/installation.md b/docs/guides/installation.md new file mode 100644 index 00000000..23cc66d3 --- /dev/null +++ b/docs/guides/installation.md @@ -0,0 +1,209 @@ +# Installation + +This guide covers all methods for installing icp-cli on your system. + +## Quick Install + +**macOS (Homebrew):** + +```bash +brew install dfinity/tap/icp-cli +``` + +**Curl** + +```bash +# install icp-cli +curl --proto '=https' --tlsv1.2 -LsSf https://github.com/dfinity/icp-cli/releases/download/v0.1.0-beta.3/icp-cli-installer.sh | sh + +# install ic-wasm which is a dependency for many recipes +curl --proto '=https' --tlsv1.2 -LsSf https://github.com/dfinity/ic-wasm/releases/download/0.9.10/ic-wasm-installer.sh | sh +``` + +**From source:** + +Cargo is required as a pre-requisite. + +```bash +git clone https://github.com/dfinity/icp-cli.git +cd icp-cli && cargo build --release +export PATH=$(pwd)/target/release:$PATH +``` + +Verify installation: + +```bash +icp --version +``` + +## Installation Methods + +### Homebrew (macOS) + +The recommended installation method for macOS: + +```bash +brew install dfinity/tap/icp-cli +``` + +To update: + +```bash +brew upgrade dfinity/tap/icp-cli +``` + +### Downloading binaries + +You can download binaries for your platform: + +- icp-cli at https://github.com/dfinity/icp-cli/releases +- ic-wasm at https://github.com/dfinity/ic-wasm/releases + +Alternatively, you can curl and run the installation scripts: + +```bash +# install icp-cli +curl --proto '=https' --tlsv1.2 -LsSf https://github.com/dfinity/icp-cli/releases/download/v0.1.0-beta.3/icp-cli-installer.sh | sh + +# install ic-wasm which is a dependency for many recipes +curl --proto '=https' --tlsv1.2 -LsSf https://github.com/dfinity/ic-wasm/releases/download/0.9.10/ic-wasm-installer.sh | sh +``` + +### Building from Source + +Building from source works on macOS, Linux, and Windows (WSL). + +#### Prerequisites + +**Rust toolchain:** + +Install Rust via [rustup](https://rustup.rs/): + +```bash +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` + +icp-cli requires Rust 1.88.0 or later (Rust 2024 edition). + +**Platform-specific dependencies:** + +| Platform | Dependencies | +|----------|--------------| +| macOS | Xcode Command Line Tools: `xcode-select --install` | +| Ubuntu/Debian | `sudo apt install build-essential pkg-config libssl-dev` | +| Fedora/RHEL | `sudo dnf install gcc pkg-config openssl-devel` | +| Arch Linux | `sudo pacman -S base-devel openssl` | + +#### Build Steps + +Clone and build: + +```bash +git clone https://github.com/dfinity/icp-cli.git +cd icp-cli +cargo build --release +``` + +The binary is at `target/release/icp`. Add it to your PATH: + +```bash +# Add to current session +export PATH=$(pwd)/target/release:$PATH + +# Or copy to a location in your PATH +cp target/release/icp ~/.local/bin/ +``` + +To update, pull the latest changes and rebuild: + +```bash +git pull +cargo build --release +``` + +### Cargo Install + +If icp-cli is published to crates.io: + +```bash +cargo install icp-cli +``` + +## Language Toolchains + +icp-cli builds canisters using your language's toolchain. Install the toolchains for the languages you'll use: + +### Rust Canisters + +Install the WebAssembly target: + +```bash +rustup target add wasm32-unknown-unknown +``` + +### Motoko Canisters + +Install [mops](https://cli.mops.one/) and initialize the toolchain: + +```bash +# Install mops (see https://cli.mops.one/ for latest instructions) +npm install -g ic-mops + +# Initialize Motoko toolchain +mops toolchain init +``` + +## Verifying Installation + +After installation, verify everything works: + +```bash +# Check icp-cli version +icp --version + +# View available commands +icp help + +# Test creating a project (optional) +icp new test-project +cd test-project +icp network start -d +icp deploy +icp network stop +cd .. +rm -rf test-project +``` + +## Troubleshooting + +**"command not found: icp"** + +The binary isn't in your PATH. Either: +- Add the directory containing `icp` to your PATH +- Use the full path to the binary + +**Build fails with OpenSSL errors** + +Install OpenSSL development libraries for your platform (see prerequisites above). + +**Build fails with "rustc too old"** + +Update Rust: + +```bash +rustup update +``` + +**Network launcher download fails** + +The network launcher is automatically downloaded on first use. If it fails: +- Check your internet connection +- Try again — transient failures are possible +- For manual installation, download from [github.com/dfinity/icp-cli-network-launcher/releases](https://github.com/dfinity/icp-cli-network-launcher/releases) and set `ICP_CLI_NETWORK_LAUNCHER_PATH` + +## Next Steps + +- [Tutorial](../tutorial.md) — Deploy your first canister +- [Local Development](local-development.md) — Day-to-day workflow + +[Browse all documentation →](../index.md) diff --git a/docs/guides/local-development.md b/docs/guides/local-development.md new file mode 100644 index 00000000..952219cb --- /dev/null +++ b/docs/guides/local-development.md @@ -0,0 +1,163 @@ +# Local Development + +This guide covers the day-to-day development workflow with icp-cli. + +## The Development Cycle + +Local development follows a simple loop: + +``` +Edit code → Build → Deploy → Test → Repeat +``` + +### Starting Your Session + +Start the local network in the background: + +```bash +icp network start -d +``` + +Verify it's running: + +```bash +icp network ping +``` + +### Making Changes + +After editing your source code, deploy the changes: + +```bash +icp deploy +``` + +This rebuilds and redeploys all canisters. Deploy specific canisters: + +```bash +icp deploy my-canister +``` + +**Tip:** `icp deploy` always builds first. If you want to verify compilation before deploying, run `icp build` separately. + +### Testing Changes + +Call methods on your canister: + +```bash +icp canister call my-canister method_name '(arguments)' +``` + +Example: + +```bash +icp canister call backend get_user '("alice")' +``` + +### Viewing Project State + +List canisters configured in this environment: + +```bash +icp canister list +``` + +View the effective project configuration: + +```bash +icp project show +``` + +## Working with Multiple Canisters + +Deploy all canisters: + +```bash +icp deploy +``` + +Deploy specific canisters: + +```bash +icp deploy frontend +icp deploy backend +``` + +Build without deploying (for verification): + +```bash +icp build # Build all +icp build frontend # Build specific canister +``` + +## Resetting State + +To start fresh with a clean network: + +```bash +# Stop the current network +icp network stop + +# Start a new network (previous state is discarded) +icp network start -d +``` + +Then redeploy your canisters: + +```bash +icp deploy +``` + +## Network Management + +Check network status: + +```bash +icp network status +``` + +View network details as JSON: + +```bash +icp network status --json +``` + +Stop the network when done: + +```bash +icp network stop +``` + +## Troubleshooting + +**Build fails with "command not found"** + +Ensure your language toolchain is installed and in PATH: +- Rust: `rustup target add wasm32-unknown-unknown` +- Motoko: `mops toolchain init` + +**Network connection fails** + +Check if the network is running: + +```bash +icp network ping +``` + +If not responding, restart: + +```bash +icp network stop +icp network start -d +``` + +**Deployment fails** + +1. Verify the build succeeded: `icp build` +2. Check network health: `icp network ping` + +## Next Steps + +- [Deploying to Mainnet](deploying-to-mainnet.md) — Go live with your canisters + +[Browse all documentation →](../index.md) diff --git a/docs/guides/managing-environments.md b/docs/guides/managing-environments.md new file mode 100644 index 00000000..e8d5121c --- /dev/null +++ b/docs/guides/managing-environments.md @@ -0,0 +1,211 @@ +# Managing Environments + +Environments let allow to deploy multiple instances of a set of canisters to the same network with each set having independent settings. This guide covers setting up development, staging, and production environments. + +## Understanding Environments + +An **environment** combines: +- A **network** to deploy to +- A set of **canisters** to deploy +- **Settings** specific to that environment + +Two implicit environments are always available: +- `local` — Uses the local managed network (default) +- `ic` — Uses the IC mainnet + +## Basic Environment Configuration + +Add environments to your `icp.yaml`: + +```yaml +canisters: + - name: frontend + build: + # ... build steps + - name: backend + build: + # ... build steps + +environments: + - name: staging + network: ic + canisters: [frontend, backend] + + - name: production + network: ic + canisters: [frontend, backend] +``` + +## Environment-Specific Settings + +Override canister settings per environment: + +```yaml +environments: + - name: staging + network: ic + canisters: [frontend, backend] + settings: + backend: + compute_allocation: 5 + environment_variables: + LOG_LEVEL: "debug" + + - name: production + network: ic + canisters: [frontend, backend] + settings: + backend: + compute_allocation: 20 + freezing_threshold: 7776000 # 90 days + environment_variables: + LOG_LEVEL: "error" +``` + +## Deploying to Environments + +Deploy to a specific environment: + +```bash +# Local development (default) +icp deploy + +# Staging +icp deploy --environment staging + +# Production +icp deploy --environment production + +# IC mainnet (using implicit ic environment) +icp deploy -e ic +``` + +## Environment-Specific Init Args + +Provide different initialization arguments per environment: + +```yaml +canisters: + - name: backend + build: + # ... build steps + init_args: "(record { mode = \"production\" })" + +environments: + - name: staging + network: ic + canisters: [backend] + init_args: + backend: "(record { mode = \"staging\" })" +``` + +## Viewing Environment Configuration + +See all configured environments: + +```bash +icp environment list +``` + +View the effective project configuration: + +```bash +icp project show +``` + +This shows all environments and their settings. + +## Working with Canister IDs + +Each environment maintains separate canister IDs. The storage location depends on network type: + +- **Managed networks** (local): `.icp/cache/mappings/.ids.json` +- **Connected networks** (IC mainnet): `.icp/data/mappings/.ids.json` + +List canisters configured for an environment: + +```bash +icp canister list --environment staging +``` + +This shows the network status of the canisters in that environment: + +```bash +icp canister status --environment staging +``` + +## Example: Full Multi-Environment Setup + +```yaml +canisters: + - name: frontend + build: + steps: + - type: script + commands: + - npm run build + sync: + steps: + - type: assets + source: dist + target: / + + - name: backend + build: + steps: + - type: script + commands: + - cargo build --target wasm32-unknown-unknown --release + - cp target/wasm32-unknown-unknown/release/backend.wasm "$ICP_WASM_OUTPUT_PATH" + +environments: + - name: staging + network: ic + canisters: [frontend, backend] + settings: + frontend: + memory_allocation: 2147483648 # 2GB + backend: + compute_allocation: 5 + reserved_cycles_limit: 5000000000000 + environment_variables: + API_ENV: "staging" + + - name: production + network: ic + canisters: [frontend, backend] + settings: + frontend: + memory_allocation: 4294967296 # 4GB + freezing_threshold: 7776000 # 90 days + backend: + compute_allocation: 20 + reserved_cycles_limit: 50000000000000 + freezing_threshold: 7776000 + environment_variables: + API_ENV: "production" +``` + +## Deployment Workflow + +A typical workflow: + +```bash +# 1. Develop locally +icp network start -d +icp build && icp deploy +# ... test changes ... + +# 2. Deploy to staging +icp deploy --environment staging +# ... verify on staging ... + +# 3. Deploy to production +icp deploy --environment production +``` + +## Next Steps + +- [Environments and Networks](../concepts/environments.md) — Understand how environments work + +[Browse all documentation →](../index.md) diff --git a/docs/guides/managing-identities.md b/docs/guides/managing-identities.md new file mode 100644 index 00000000..bec5c2de --- /dev/null +++ b/docs/guides/managing-identities.md @@ -0,0 +1,196 @@ +# Managing Identities + +Identities represent who you are when interacting with the Internet Computer. This guide covers creating, importing, and using identities with icp-cli. + +## Understanding Identities + +An identity consists of: +- A **private key** — Used to sign messages +- A **principal** — Your public identifier derived from the key + +Identities are stored in `~/.config/icp/identity/`. + +## Creating an Identity + +Create a new identity: + +```bash +icp identity new my-identity +``` + +This generates a new key pair and stores it securely. + +### Saving the Seed Phrase + +To back up your identity, save the seed phrase: + +```bash +icp identity new my-identity --output-seed seed.txt +``` + +Store `seed.txt` securely — it can restore your identity. + +## Listing Identities + +View all available identities: + +```bash +icp identity list +``` + +## Setting the Default Identity + +Set which identity to use by default: + +```bash +icp identity default my-identity +``` + +Check the current default: + +```bash +icp identity default +``` + +## Viewing Your Principal + +Display the principal for the current identity: + +```bash +icp identity principal +``` + +For a specific identity: + +```bash +icp identity principal --identity other-identity +``` + +## Importing Identities + +### From a PEM File + +```bash +icp identity import my-identity --from-pem ./key.pem +``` + +### From a Seed Phrase + +```bash +icp identity import my-identity --from-seed-file ./seed.txt +``` + +Or enter interactively: + +```bash +icp identity import my-identity --read-seed-phrase +``` + +## Storage Options + +When creating or importing, choose how to store the key: + +### Keyring (Default, Recommended) + +Uses your system's secure keyring: + +```bash +icp identity new my-identity --storage keyring +``` + +### Password-Protected + +Encrypts the key with a password: + +```bash +icp identity new my-identity --storage password +``` + +You'll be prompted for the password when using this identity. + +### Plaintext (Not Recommended) + +Stores the key unencrypted: + +```bash +icp identity new my-identity --storage plaintext +``` + +Only use for testing or non-sensitive deployments. + +## Using Identities per Command + +Override the default identity for a single command: + +```bash +icp deploy --identity production-deployer -e ic +``` + +## Using Password Files + +For automation, provide passwords via file: + +```bash +icp deploy --identity my-identity --identity-password-file ./password.txt +``` + +## Identity Best Practices + +**Development:** +- Use a dedicated development identity +- Plaintext storage is acceptable for local testing + +**Production:** +- Use keyring or password-protected storage +- Keep seed phrases in secure, offline storage +- Use separate identities for different environments +- Limit who has access to production identities + +**CI/CD:** +- Store keys as secrets in your CI system +- Use password files for automated deployments +- Consider separate identities with limited permissions + +## Managing Controllers + +Your identity's principal can be a controller of canisters. View canister controllers: + +```bash +icp canister settings show -n ic +``` + +Add a controller: + +```bash +icp canister settings update --add-controller -n ic +``` + +Remove a controller: + +```bash +icp canister settings update --remove-controller -n ic +``` + +## Troubleshooting + +**"Not a controller"** + +Your identity isn't authorized to manage this canister. You need to be added as a controller by an existing controller. + +**"Password required"** + +The identity uses password-protected storage. Either enter the password when prompted or use `--identity-password-file`. + +**"Identity not found"** + +Check available identities: + +```bash +icp identity list +``` + +## Next Steps + +- [Deploying to IC Mainnet](deploying-to-mainnet.md) — Use your identity to deploy + +[Browse all documentation →](../index.md) diff --git a/docs/guides/tokens-and-cycles.md b/docs/guides/tokens-and-cycles.md new file mode 100644 index 00000000..744924bd --- /dev/null +++ b/docs/guides/tokens-and-cycles.md @@ -0,0 +1,196 @@ +# Tokens and Cycles + +This guide covers managing ICP tokens and cycles with icp-cli. + +## Overview + +The Internet Computer uses two types of currency: + +| Currency | Purpose | Used For | +|----------|---------|----------| +| **ICP** | Governance token | Trading, staking, converting to cycles | +| **Cycles** | Computational fuel | Running canisters, paying for storage and compute | + +Canisters consume cycles to operate. To deploy and run canisters on the IC mainnet, you need cycles. + +## Checking Balances + +### ICP Token Balance + +Check your ICP balance: + +```bash +# On IC mainnet +icp token balance -n ic + +# On local network (for testing) +icp token balance +``` + +### Cycles Balance + +Check your cycles balance: + +```bash +# On IC mainnet +icp cycles balance -n ic + +# On local network +icp cycles balance +``` + +### Canister Cycles Balance + +Check how many cycles a specific canister has: + +```bash +# On IC mainnet +icp canister status -n ic +``` + +The output includes the canister's cycles balance. + +## Transferring ICP + +Send ICP tokens to another principal: + +```bash +# On IC mainnet +icp token transfer -n ic +``` + +Example: + +```bash +# Send 1 ICP +icp token transfer 1 aaaaa-aa -n ic + +# Send 0.5 ICP +icp token transfer 0.5 xxxxx-xxxxx-xxxxx-xxxxx-cai -n ic +``` + +The receiver can be a principal ID or account identifier. + +## Converting ICP to Cycles + +**Note:** You need ICP tokens before you can convert them to cycles. See [Getting ICP and Cycles](#getting-icp-and-cycles) below if you don't have ICP yet. + +Convert ICP tokens to cycles for use with canisters: + +```bash +# Convert a specific amount of ICP on IC Mainnet +icp cycles mint --icp 1 -n ic + +# Or request a specific amount of cycles (ICP calculated automatically) on IC Mainnet +icp cycles mint --cycles 1000000000000 -n ic +``` + +The conversion rate is determined by the current ICP/XDR exchange rate. One trillion cycles (1T = 1,000,000,000,000) costs approximately 1 XDR worth of ICP. + +## Topping Up Canisters + +Add cycles to a canister to keep it running: + +```bash +icp canister top-up --amount 1000000000000 -n ic +``` + +The `--amount` is specified in cycles (not ICP). + +### Monitoring Cycles + +Regularly check canister cycles to avoid running out: + +```bash +# Check all canisters in an environment +icp canister status -e my-env + +# Check specific canister +icp canister status my-canister -e my-env +``` + +## Getting ICP and Cycles + +### On IC Mainnet + +To get ICP tokens: + +1. **Receive from another wallet** — Share your principal: `icp identity principal` +2. **Purchase on an exchange** — Buy ICP and withdraw to your principal + +To get cycles: + +1. **Convert ICP** — Use `icp cycles mint` after acquiring ICP +2. **Receive cycles** — Someone can transfer cycles to your principal via the cycles ledger + +### On Local Network + +Local networks have unlimited cycles for testing. The default identity is automatically funded. + +## Working with Different Tokens + +icp-cli supports ICRC-1 tokens beyond ICP: + +```bash +# Check balance of a specific token on IC Mainnet +icp token balance -n ic + +# Transfer a specific token on IC Mainnet +icp token transfer 100 -n ic +``` + +Replace `` with the canister ID of the token ledger. + +## Using Different Identities + +Specify which identity to use for token operations: + +```bash +# Check balance for a specific identity on IC Mainnet +icp token balance --identity my-other-identity -n ic + +# Transfer using a specific identity on IC Mainnet +icp token transfer 1 --identity my-wallet -n ic +``` + +## Troubleshooting + +**"Insufficient balance"** + +Your account doesn't have enough ICP or cycles. Check your balance: + +```bash +# For IC Mainnet +icp token balance -n ic +icp cycles balance -n ic + +# For the local network +icp token balance -n local +icp cycles balance -n local +``` + +**"Canister out of cycles"** + +Top up the canister: + +```bash +# On IC mainnet +icp canister top-up --amount 1000000000000 -n ic + +# In an environment callend `prod-env` +icp canister top-up --amount 1000000000000 -e prod-env +``` + +**Transfer fails** + +Verify: +- The receiver address is correct +- You have sufficient balance (including fees) +- You're using the correct identity + +## Next Steps + +- [Deploying to Mainnet](deploying-to-mainnet.md) — Use cycles to deploy canisters +- [Managing Identities](managing-identities.md) — Manage keys and principals + +[Browse all documentation →](../index.md) diff --git a/docs/guides/using-recipes.md b/docs/guides/using-recipes.md new file mode 100644 index 00000000..ebbd0e9d --- /dev/null +++ b/docs/guides/using-recipes.md @@ -0,0 +1,168 @@ +# Using Recipes + +Recipes are reusable build templates that simplify canister configuration. Instead of writing build steps from scratch, you reference a recipe that expands into the full configuration. + +## Why Use Recipes? + +- **Less boilerplate** — Common patterns are pre-configured +- **Best practices** — Recipes encode recommended build settings +- **Consistency** — Share build configurations across projects +- **Maintainability** — Update the recipe, update all projects + +## Using Official Recipes + +DFINITY maintains recipes for common use cases at [github.com/dfinity/icp-cli-recipes](https://github.com/dfinity/icp-cli-recipes). + +You can reference recipes by pointing to a URL. For the official recipes, you can use a shorthand for example these recipe types are equivalent: +* `@dfinity/rust` +* `https://github.com/dfinity/icp-cli-recipes/releases/download/rust-latest/recipe.hbs` + +### Rust Canister + +For building a rust canister: + +```yaml +canisters: + - name: backend + recipe: + type: "@dfinity/rust" + configuration: + package: backend +``` + +### Motoko Canister + +For building a motoko canister: + +```yaml +canisters: + - name: backend + recipe: + type: "@dfinity/motoko" + configuration: + entry: src/main.mo +``` + +### Assets Canister + +For deploying an asset canister with frontend assets: + +```yaml +canisters: + - name: frontend + recipe: + type: "@dfinity/asset-canister" + configuration: + source: dist +``` + +### Pre-built WASM + +For deploying a prebuilt WASM: + +```yaml +canisters: + - name: my-canister + recipe: + type: "@dfinity/prebuilt" + configuration: + path: ./my-canister.wasm + sha256: d7c1aba0de1d7152897aeca49bd5fe89a174b076a0ee1cc3b9e45fcf6bde71a6 +``` + +## Recipe Versioning + +Pin recipes to specific versions for reproducible builds. These two types are equivalent: + +* `@dfinity/rust@v3.0.0` +* `https://github.com/dfinity/icp-cli-recipes/releases/download/rust-v3.0.0/recipe.hbs` + +```yaml +canisters: + - name: backend + recipe: + type: "@dfinity/rust@v3.0.0" + configuration: + package: backend +``` + +## Local Recipes + +You can create project-specific recipes as Handlebars templates. This can be useful when multiple canisters +in your project share the same build patterns. + +```yaml +# recipes/my-rust-canister.hbs +build: + steps: + - type: script + commands: + - cargo build --package {{package}} --target wasm32-unknown-unknown --release + - cp target/wasm32-unknown-unknown/release/{{package}}.wasm "$ICP_WASM_OUTPUT_PATH" +``` + +Reference it in your `icp.yaml`: + +```yaml +canisters: + - name: backend + recipe: + type: file://recipes/my-rust-canister.hbs + configuration: + package: my-pkg +``` + +## Remote Recipes + +Reference recipes from any URL: + +```yaml +canisters: + - name: backend + recipe: + type: https://example.com/recipes/rust-optimized.hbs + sha256: 17a05e36278cd04c7ae6d3d3226c136267b9df7525a0657521405e22ec96be7a + configuration: + package: backend +``` + +Always include `sha256` for remote recipes to ensure integrity. + +## Viewing Expanded Configuration + +See what a recipe expands to: + +```bash +icp project show +``` + +This displays the effective configuration after all recipes are rendered. + +## Recipe Configuration Options + +Each recipe defines its own configuration schema. Check the recipe's documentation or source for available options. + +## Combining Recipes with Settings + +Recipes only define the `build` and `sync` configurations of the canister. You can add canister settings as a separate field +in the configuration file. eg: + +```yaml +canisters: + - name: backend + recipe: + type: "@dfinity/rust" + configuration: + package: backend + settings: + compute_allocation: 10 + environment_variables: + API_KEY: "secret" +``` + +## Next Steps + +- [Recipes](../concepts/recipes.md) — Understand how recipes work +- [Creating Recipes](creating-recipes.md) — Build custom recipes + +[Browse all documentation →](../index.md) diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..3831db52 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,44 @@ +# icp-cli Documentation + +Build and deploy applications on the Internet Computer. + +## Start Here + +**New to icp-cli?** Follow the [Tutorial](tutorial.md) to deploy your first canister in under 10 minutes. + +## Guides + +Step-by-step instructions for common tasks: + +- [Installation](guides/installation.md) — Install icp-cli on your system +- [Local Development](guides/local-development.md) — The edit-build-deploy cycle +- [Deploying to Mainnet](guides/deploying-to-mainnet.md) — Go live on the Internet Computer +- [Tokens and Cycles](guides/tokens-and-cycles.md) — Manage ICP tokens and cycles +- [Managing Environments](guides/managing-environments.md) — Dev, staging, production workflows +- [Managing Identities](guides/managing-identities.md) — Keys and authentication +- [Using Recipes](guides/using-recipes.md) — Reusable build templates +- [Creating Recipes](guides/creating-recipes.md) — Build custom recipes +- [Creating Templates](guides/creating-templates.md) — Author project templates + +## Concepts + +Understand how icp-cli works: + +- [Project Model](concepts/project-model.md) — How configuration is organized +- [Build, Deploy, Sync](concepts/build-deploy-sync.md) — The deployment lifecycle +- [Environments and Networks](concepts/environments.md) — Deployment targets explained +- [Recipes](concepts/recipes.md) — Templated build configurations + +## Reference + +Complete technical specifications: + +- [CLI Reference](reference/cli.md) — All commands and flags +- [Configuration Reference](reference/configuration.md) — icp.yaml schema +- [Canister Settings](reference/canister-settings.md) — All settings options + +## Additional Resources + +- [Containerized Networks](containers.md) — Docker-based local networks +- [Migrating from dfx](migration/from-dfx.md) — For existing dfx users +- [Examples](../examples/) — Sample projects for various use cases diff --git a/docs/migration/from-dfx.md b/docs/migration/from-dfx.md new file mode 100644 index 00000000..5aab514c --- /dev/null +++ b/docs/migration/from-dfx.md @@ -0,0 +1,429 @@ +# Migrating from dfx + +This guide helps developers familiar with dfx transition to icp-cli. + +## Key Differences + +### Configuration Format + +| Aspect | dfx | icp-cli | +|--------|-----|---------| +| Config file | `dfx.json` | `icp.yaml` | +| Format | JSON | YAML | +| Canisters | Object with canister names as keys | Array of canister definitions | + +### Deployment Model + +**dfx** deploys to networks directly: +```bash +dfx deploy --network ic +``` + +**icp-cli** deploys to environments (which reference networks): +```bash +icp deploy --environment production + +# or use the implicit ic environment: +icp deploy --environment ic +icp deploy -e ic +``` + +Environments add a layer of abstraction, allowing different settings for the same network. + +### Recipe System + +icp-cli introduces recipes — reusable build templates. Instead of dfx's built-in canister types, you reference recipes: + +```yaml +# dfx.json style (not supported) +"my_canister": { + "type": "rust", + "package": "my_canister" +} + +# icp-cli style +canisters: + - name: my_canister + recipe: + type: "@dfinity/rust" + configuration: + package: my_canister +``` + +### Build Process + +dfx has built-in build logic. icp-cli delegates to the appropriate toolchain as specified in the +build configuration or through the use of a recipe. + +```yaml +canisters: + - name: backend + build: + steps: + - type: script + commands: + - cargo build --target wasm32-unknown-unknown --release + - cp target/wasm32-unknown-unknown/release/backend.wasm "$ICP_WASM_OUTPUT_PATH" +``` + +### Build parallelism + +dfx requires users to specify the inter canister dependencies so it can build canisters in order. + +icp-cli assumes users will use canister environment variables to connect canisters and builds all canisters in parallel. + +### Local networks + +| Operation | dfx | icp-cli | +|-----------|-----|---------| +| Launching a local network | Shared local network for all projects | Local network is local to the project | +| System canisters | Requires that you pass additional parameters to setup system canisters | Launches a network with system canisters and seeds accounts with ICP and Cycles | +| Tokens | User must mint tokens | Anonymous principal and local account are seeded with tokens | +| docker support | N/A | Supports launching a dockerized network | + + +## Command Mapping + +| Task | dfx | icp-cli | +|------|-----|---------| +| Create project | `dfx new my_project` | `icp new my_project` | +| Start local network | `dfx start --background` | `icp network start -d` | +| Stop local network | `dfx stop` | `icp network stop` | +| Build canister | `dfx build my_canister` | `icp build my_canister` | +| Deploy all | `dfx deploy` | `icp deploy` | +| Deploy to mainnet | `dfx deploy --network ic` | `icp deploy -e ic` | +| Call canister | `dfx canister call my_canister method '(args)'` | `icp canister call my_canister method '(args)'` | +| Get canister ID | `dfx canister id my_canister` | `icp canister status my_canister --id-only` | +| List canisters | `dfx canister ls` | `icp canister list` | +| Canister status | `dfx canister status my_canister` | `icp canister status my_canister` | +| Create identity | `dfx identity new my_id` | `icp identity new my_id` | +| Use identity | `dfx identity use my_id` | `icp identity default my_id` | +| Show principal | `dfx identity get-principal` | `icp identity principal` | + +## Converting dfx.json to icp.yaml + +### Basic Rust Canister + +**dfx.json:** +```json +{ + "canisters": { + "backend": { + "type": "rust", + "package": "backend", + "candid": "src/backend/backend.did" + } + } +} +``` + +**canister.yaml:** +```yaml +name: backend +recipe: + type: "@dfinity/rust" + configuration: + package: backend + candid: "src/backend/backend.did" +``` + +### Basic Motoko Canister + +**dfx.json:** +```json +{ + "canisters": { + "backend": { + "type": "motoko", + "main": "src/backend/main.mo" + } + } +} +``` + +**canister.yaml:** +```yaml +name: backend +recipe: + type: "@dfinity/motoko" + configuration: + entry: src/backend/main.mo + candid: src/backend/candid.did +``` + +### Asset Canister + +**dfx.json:** +```json +{ + "canisters": { + "frontend": { + "type": "assets", + "source": ["dist"] + } + } +} +``` + +**canister.yaml:** +```yaml +name: frontend +recipe: + type: "@dfinity/asset-canister" + configuration: + source: dist +``` + +### Multi-Canister Project + +**dfx.json:** +```json +{ + "canisters": { + "frontend": { + "type": "assets", + "source": ["dist"], + "dependencies": ["backend"] + }, + "backend": { + "type": "rust", + "package": "backend" + } + } +} +``` + +**icp.yaml:** +```yaml +canisters: + - name: frontend + recipe: + type: "@dfinity/assets" + configuration: + source: dist + + - name: backend + recipe: + type: "@dfinity/rust" + configuration: + package: backend +``` + +Note: icp-cli doesn't have explicit dependencies between canisters. Deploy order is determined automatically or you can deploy specific canisters. + +### Network Configuration + +**dfx.json:** +```json +{ + "networks": { + "staging": { + "providers": ["https://ic0.app"], + "type": "persistent" + } + } +} +``` + +**icp.yaml:** +```yaml +networks: + - name: staging + mode: connected + url: https://ic0.app + +environments: + - name: staging + network: staging + canisters: [frontend, backend] +``` + +## Features Not in icp-cli + +Some dfx features work differently or aren't directly available: + +| dfx Feature | icp-cli Equivalent | +|-------------|-------------------| +| `dfx.json` defaults | Use recipes or explicit configuration | +| Canister dependencies | Use bindings compatible with Canister Environment Variables | +| `dfx generate` | Use language-specific tooling | +| `dfx ledger` | `icp token` commands | +| `dfx wallet` | Cycles managed differently | +| `dfx upgrade` | Reinstall icp-cli | + +## Migrating Identities + +dfx identities can be imported into icp-cli. Both tools use compatible key formats. + +### Identity Storage Locations + +| Tool | Location | +|------|----------| +| dfx | `~/.config/dfx/identity//identity.pem` | +| icp-cli | `~/.config/icp/identity/` | + +### Import a dfx Identity + +```bash +# Import an unencrypted dfx identity +icp identity import my-identity --from-pem ~/.config/dfx/identity/my-identity/identity.pem + +# Verify the principal matches +dfx identity get-principal --identity my-identity +icp identity principal --identity my-identity +``` + +Both commands should display the same principal. + +### Import an Encrypted dfx Identity + +If your dfx identity is password-protected: + +```bash +icp identity import my-identity \ + --from-pem ~/.config/dfx/identity/my-identity/identity.pem \ + --decryption-password-from-file password.txt +``` + +Or enter the password interactively when prompted. + +### Migrate All Identities + +To migrate all dfx identities: + +```bash +# List dfx identities +ls ~/.config/dfx/identity/ + +# Import each one +for id in $(ls ~/.config/dfx/identity/); do + if [ -f ~/.config/dfx/identity/$id/identity.pem ]; then + echo "Importing $id..." + icp identity import $id --from-pem ~/.config/dfx/identity/$id/identity.pem + fi +done + +# Verify +icp identity list +``` + +### Setting the Default Identity + +After importing, set your default identity: + +```bash +icp identity default my-identity +``` + +### Identity Storage Options + +When importing, choose how icp-cli stores the key: + +```bash +# System keyring (recommended, default) +icp identity import my-id --from-pem key.pem --storage keyring + +# Password-protected file +icp identity import my-id --from-pem key.pem --storage password + +# Plaintext file (not recommended for production) +icp identity import my-id --from-pem key.pem --storage plaintext +``` + +## Migration Checklist + +A complete migration involves these steps: + +### 1. Create icp.yaml + +Create `icp.yaml` in your project root using the conversion examples above. + +### 2. Migrate Identities + +Import the identities you use for this project: + +```bash +icp identity import deployer --from-pem ~/.config/dfx/identity/deployer/identity.pem +``` + +### 3. Test Locally + +```bash +icp network start -d +icp build +icp deploy +icp canister call my-canister test_method '()' +``` + +### 4. Migrate Canister IDs (Optional) + +If you have existing canisters on mainnet that you want to continue managing with icp-cli, create a mapping file to preserve their IDs. + +Create `.icp/data/mappings/ic.ids.json`: + +```json +{ + "frontend": "xxxxx-xxxxx-xxxxx-xxxxx-cai", + "backend": "yyyyy-yyyyy-yyyyy-yyyyy-cai" +} +``` + +Get the canister IDs from your dfx project: + +```bash +dfx canister --network ic id frontend +dfx canister --network ic id backend +``` + +### 5. Verify Mainnet Access + +```bash +# Check you can reach IC mainnet +icp network ping ic + +# Verify identity has correct principal +icp identity principal + +# Check canister status (if you migrated IDs) +icp canister status my-canister -e ic +``` + +### 6. Update CI/CD + +Replace dfx commands with icp-cli equivalents in your CI/CD scripts: + +**Before (dfx):** +```yaml +steps: + - run: dfx start --background + - run: dfx deploy + - run: dfx deploy --network ic +``` + +**After (icp-cli):** +```yaml +steps: + - run: icp network start -d + - run: icp deploy + - run: icp deploy -e ic +``` + +### 7. Update Documentation + +Update any project documentation that references dfx commands. + +## Keeping Both Tools + +During migration, you can use both tools side-by-side: + +- dfx and icp-cli use separate configuration files (`dfx.json` vs `icp.yaml`) +- Identity files can be shared by importing into icp-cli +- Canister IDs are stored in different locations + +This allows gradual migration without disrupting existing workflows. + +## Getting Help + +- [Tutorial](../tutorial.md) — Quick start guide +- [Concepts](../concepts/index.md) — Understand the icp-cli model +- [Configuration Reference](../reference/configuration.md) — Full icp.yaml documentation diff --git a/docs/project-configuration.md b/docs/project-configuration.md deleted file mode 100644 index 4d1a9f63..00000000 --- a/docs/project-configuration.md +++ /dev/null @@ -1,518 +0,0 @@ -# Project Configuration Guide - -This guide provides a comprehensive reference for configuring ICP projects using the `icp.yaml` file. The configuration file defines how your canisters are built, deployed, and managed across different environments. - -## Overview - -The `icp.yaml` file describes the configuration of your ICP project. It supports: -- Single and multi-canister projects -- Custom build processes and recipes -- Environment-specific deployments -- Network configuration -- Canister settings and metadata - -See the schema reference in [./docs/schemas/icp-yaml-schema.json](./docs/schemas/icp-yaml-schema.json) - -## Project Lifecycle - -When working with ICP projects, your canisters go through several distinct phases during development and deployment: - -### Building Canisters - -The build phase compiles your source code and generates WASM bytecode files that can run on the Internet Computer. During this phase: - -- Build steps defined in your configuration are executed in sequence. -- The result of this step is compiled WASM and possibly some other assets (for eg, static files in the case of an asset canister serving a frontend). -- icp-cli does not concern itself with the compilation process, instead it delegates to the appropriate toolchain. -- Ideally, the WASM and assets produced are reproducible and don't contain any hard coded deployment specific information. -- The toolchains are responsible for detecting whether building is necessary and which version of the compiler to use. - -### Creating Canisters - -This is a one-time setup phase that occurs automatically when deploying to a network for the first time: - -- Empty canister instances are created on the target network. -- Each canister receives a unique canister ID. -- Initial cycles are allocated to cover the canister's operations. -- Canister settings (memory limits, compute allocation, etc.) are applied. - -### Deploying Canisters - -Deployment updates the WASM code running in your existing canisters: - -- The compiled WASM bytecode is installed into the canister. -- Previous WASM code is replaced with the new version. -- Canister state persists across deployments (unless explicitly reset). -- Environment variables and settings are updated if changed. - -### Syncing Canisters - -The sync phase handles post-deployment operations to synchronize canister state. This is dependent -on the type of canister itself. A typical case is uploading static assets to an asset canister. - - -These phases work together to provide a complete deployment pipeline from source code to a running canister on the Internet Computer. - - -## Basic Structure - -### Single Canister Project - -```yaml -canisters: - - name: my-canister - build: - steps: - - type: script - commands: - - cargo build --target wasm32-unknown-unknown --release - - mv target/wasm32-unknown-unknown/release/my_canister.wasm "$ICP_WASM_OUTPUT_PATH" -``` - -### Multi-Canister Project - -```yaml -canisters: - - canisters/* # Glob pattern - - path/to/specific/canister.yaml - - name: inline-canister # Inline definition - build: - steps: - - type: pre-built - path: dist/canister.wasm -``` - -## Configuration Sections - -### Canister Configuration - -#### Inline Canister Definition - -```yaml -canisters: - - name: my-canister - - # Build configuration (required) - build: - steps: - - type: script - commands: - - echo "Building canister..." - - # Your build commands here - - # Sync configuration (optional) - sync: - steps: - - type: assets - source: www - target: / - - # Canister settings (optional) - settings: - compute_allocation: 1 - memory_allocation: 4294967296 # 4GB in bytes - freezing_threshold: 2592000 # 30 days in seconds - reserved_cycles_limit: 1000000000000 - wasm_memory_limit: 1073741824 # 1GB in bytes - wasm_memory_threshold: 536870912 # 512MB in bytes - environment_variables: - API_URL: "https://api.example.com" - DEBUG: "false" -``` - -#### External Canister References - -```yaml -canisters: - - canisters/* # All YAML files in canisters/ directory - - frontend/canister.yaml # Specific file path - - backend/*.yaml # Glob pattern for backend canisters -``` - -### Build Steps - -Build steps define how your canister WASM is created. Multiple step types are supported: - -#### Script Build Steps - -Execute custom shell commands: - -```yaml -build: - steps: - - type: script - commands: - - echo "Starting build..." - - cargo build --target wasm32-unknown-unknown --release - - mv target/wasm32-unknown-unknown/release/my_canister.wasm "$ICP_WASM_OUTPUT_PATH" - - echo "Build complete!" -``` - -**Environment Variables Available in Scripts:** -- `ICP_WASM_OUTPUT_PATH`: Path where the final WASM should be placed -- `ICP_PROJECT_ROOT`: Root directory of the project -- Standard shell environment variables - -#### Pre-built Build Steps - -Use an existing WASM file: - -```yaml -build: - steps: - - type: pre-built - path: dist/my_canister.wasm - sha256: a1b2c3... # Optional integrity check -``` - -#### Assets Build Steps - -Bundle static assets into your canister: - -```yaml -build: - steps: - - type: assets - source: www # Source directory - target: / # Target path in canister - include_patterns: # Optional: files to include - - "*.html" - - "*.css" - - "*.js" - exclude_patterns: # Optional: files to exclude - - "*.md" - - "test/**" -``` - -### Sync Steps - -Sync steps handle post-deployment operations, typically for asset canisters: - -```yaml -sync: - steps: - - type: assets - source: www - target: / - # Upload static files after canister deployment -``` - -### Recipe System - -Recipes provide reusable, templated build configurations. The DFINITY foundation maintains -a set of recipes at https://github.com/dfinity/icp-cli-recipes, you can also host your own -or even refer to a local recipe file. - -Recipes are essentially handlebar templates that take a few paramters and render into build+sync steps. - -In a manifest they are referred to through the `type` field that can have one of these formats: - -#### Local Recipes - -A local path to a handlebar template, in this case a file called "myrecipe.hb.yaml" - -```yaml -canister: - name: my-canister - recipe: - type: ./myrecipe.hb.yaml - configuration: # Configuration passed to the template - package: my-canister -``` - -#### Remote Recipes - -A URL to a handlebar template. - -```yaml -canister: - name: my-canister - recipe: - type: https://recipes.example.com/rust-optimized.hb.yaml - sha256: 17a05e36278cd04c7ae6d3d3226c136267b9df7525a0657521405e22ec96be7a - configuration: # Configuration passed to the template - package: my-canister -``` - -#### From a registry - -Pointing to a known registry. In this particular case, `@dfinity` is mapped to https://github.com/dfinity/icp-cli-recipes -and `prebuilt` points to https://github.com/dfinity/icp-cli-recipes/releases/tag/prebuilt-v2.0.0 - -```yaml -canisters: - - name: my-canister-with-version - recipe: - type: "@dfinity/prebuilt@v2.0.0" - configuration: - path: ../icp-pre-built/dist/hello_world.wasm - sha256: d7c1aba0de1d7152897aeca49bd5fe89a174b076a0ee1cc3b9e45fcf6bde71a6 -``` - -### Networks - -An ICP network that icp-cli can interact with. -There are two types of networks: -- managed - this is a network whose lifecycle icp-cli is responsible for. -- connected - A remote network that is hosted, this could be IC mainnet or a remote instance of pocket-ic serving as a long lived testnet. - -You can define your own networks. There are two implicit networks: -- local - A managed network that is spun up with the network launcher and typically used for local development. This network can be overridden in your icp.yaml if you need custom configuration (e.g., different port, connecting to an existing network). -- ic - The IC mainnet, production network. This network is protected and cannot be overridden to prevent accidental deployment to production with incorrect settings. - -#### Overriding the Local Network - -The default "local" network uses `localhost:8000` as a managed network. You can override this if you need different configuration: - -**Example: Custom port** -```yaml -networks: - - name: local - mode: managed - gateway: - port: 9999 -``` - -**Example: Connect to existing network** -```yaml -networks: - - name: local - mode: connected - url: http://192.168.1.100:8000 - root-key: -``` - -**Important**: The "ic" network cannot be overridden for safety reasons. Attempting to define a network named "ic" will result in an error. - -#### Defining Custom Networks - -```yaml -networks: - # Inline network definition - - name: local-testnet - mode: managed - gateway: - host: 127.0.0.1 - port: 4943 - - # Reference to network file - - networks/staging.yaml - - networks/*.yaml # All network files in directory -``` - -#### Network Types - -**Managed Networks (Local Development):** -```yaml -name: local-dev -mode: managed -gateway: - host: 127.0.0.1 - port: 4943 -``` - -**Managed Docker Networks:** -```yaml -name: local-dev -mode: managed -image: ghcr.io/dfinity/icp-cli-network-launcher -port-mapping: - 4943:4943 -``` -See the [containers docs](./containers.md). - -**Connected Networks:** -```yaml -name: ic-mainnet -mode: connected -gateway: - url: https://ic0.app -``` - -### Environments - -Environments link canisters to networks with specific settings. For example, your project might have a couple of canisters -and you might define 3 different environments: - -- local - that you use for development against a managed local network -- ic-stage - A staging environment that is deployed to the IC mainnet -- ic - Your production environment deployed to the IC mainnet - -There are implicit environments: -- `local` - Assumes the local network and assumed to be the default -- `ic` - Assumes the IC mainnet - -Canisters can have different settings in each environment. Settings specified at the environment level will override any settings defined at the canister level. - -Example configuration: - -```yaml -environments: - - name: development - network: local-dev - canisters: - - frontend - - backend - settings: - frontend: - memory_allocation: 1073741824 # 1GB - backend: - compute_allocation: 5 - environment_variables: - MY_ENV_VAR: "some value" - - - name: production - network: ic-mainnet - canisters: - - frontend - - backend - settings: - frontend: - memory_allocation: 4294967296 # 4GB - freezing_threshold: 7776000 # 90 days - backend: - compute_allocation: 10 - reserved_cycles_limit: 10000000000000 - environment_variables: - MY_ENV_VAR: "some value" -``` - -## Canister Settings Reference - -### Compute and Memory Allocation - -```yaml -settings: - # Compute allocation (0-100): Guaranteed compute capacity percentage - compute_allocation: 5 - - # Memory allocation in bytes: Fixed memory reservation - # Dynamic allocation is used if memory_allocation is not set - memory_allocation: 4294967296 # 4GB - - # Freezing threshold in seconds: Time before canister freezes due to low cycles - freezing_threshold: 2592000 # 30 days - - # Reserved cycles limit: Maximum cycles the canister can consume - reserved_cycles_limit: 1000000000000 # 1T cycles - - # WASM memory limit in bytes: Maximum heap size for WASM module - wasm_memory_limit: 1073741824 # 1GB - - # WASM memory threshold in bytes: Triggers low-memory callback - wasm_memory_threshold: 536870912 # 512MB -``` - -### Canister Environment Variables - -Canister Environment Variables are variables available to your canister at *runtime*. -They allow compiling once and running the same WASM with different configuration. - -```yaml -settings: - environment_variables: - NODE_ENV: "production" - API_URL: "https://api.example.com" - FEATURE_FLAGS: "advanced_mode=true,beta_features=false" - CORS_ORIGINS: "https://myapp.com,https://staging.myapp.com" -``` - -### Initialization Arguments - -Specify arguments passed to the canister during installation. These arguments are provided to the canister's `init` function when the WASM module is first installed, and to `post_upgrate` when upgrading a canister's WASM module. - -```yaml -canisters: - - name: my-canister - build: - steps: - - type: pre-built - path: ./canister.wasm - - # Init args as Candid text format - init_args: "(record { owner = principal \"aaaaa-aa\"; name = \"My Canister\" })" - - # Or as hex-encoded bytes - # init_args: "4449444c016d7b0100010203" -``` - -The `init_args` field accepts a string that can be in one of two formats: - -1. **Candid text format**: Standard Candid notation like `(42)`, `(record { field = "value" })`, etc. -2. **Hex-encoded bytes**: If the string is valid hexadecimal, it will be decoded as raw bytes - -#### Environment-Specific Init Args - -Override init args for specific canisters per environment. This is useful for providing different configuration values for development, staging, and production deployments: - -```yaml -canisters: - - name: backend - build: - steps: - - type: pre-built - path: ./backend.wasm - - # Default init args (production settings for security) - init_args: "(record { mode = \"production\"; debug = false })" - -environments: - - name: development - network: local - canisters: [backend] - - # Override init args for development - init_args: - backend: "(record { mode = \"development\"; debug = true })" -``` - -## Advanced Configuration Patterns - -### Multi-Environment Setup - -```yaml -# Root icp.yaml -canisters: - - frontend/canister.yaml - - backend/canister.yaml - -networks: - - name: local - mode: managed - - name: testnet - mode: connected - gateway: - url: https://testnet.ic0.app - - name: mainnet - mode: connected - gateway: - url: https://ic0.app - -environments: - - name: dev - network: local - canisters: [frontend, backend] - - - name: test - network: testnet - canisters: [frontend, backend] - settings: - frontend: - memory_allocation: 2147483648 # 2GB - - - name: prod - network: mainnet - canisters: [frontend, backend] - settings: - frontend: - memory_allocation: 4294967296 # 4GB - compute_allocation: 10 - backend: - compute_allocation: 20 - reserved_cycles_limit: 50000000000000 -``` - -## Migration from dfx.json - -TODO - diff --git a/docs/reference/canister-settings.md b/docs/reference/canister-settings.md new file mode 100644 index 00000000..dbb714e2 --- /dev/null +++ b/docs/reference/canister-settings.md @@ -0,0 +1,214 @@ +# Canister Settings Reference + +Complete reference for all canister settings available in icp-cli. + +## Overview + +Canister settings control resource allocation, behavior, and runtime configuration. They can be specified: + +1. At the **canister level** in `icp.yaml` or `canister.yaml` +2. At the **environment level** to override per-environment + +## Settings + +### compute_allocation + +Guaranteed percentage of compute capacity. + +| Property | Value | +|----------|-------| +| Type | Integer | +| Range | 0-100 | +| Default | 0 (best effort) | + +```yaml +settings: + compute_allocation: 10 +``` + +Higher values guarantee more compute but cost more cycles. + +### memory_allocation + +Fixed memory reservation in bytes. + +| Property | Value | +|----------|-------| +| Type | Integer | +| Unit | Bytes | +| Default | Dynamic allocation | + +```yaml +settings: + memory_allocation: 4294967296 # 4GB +``` + +If not set, the canister uses dynamic memory allocation. + +### freezing_threshold + +Time in seconds before the canister freezes due to low cycles. + +| Property | Value | +|----------|-------| +| Type | Integer | +| Unit | Seconds | +| Default | 2592000 (30 days) | + +```yaml +settings: + freezing_threshold: 7776000 # 90 days +``` + +The canister freezes if its cycles balance would be exhausted within this threshold. + +### reserved_cycles_limit + +Maximum cycles the canister can hold in reserve. + +| Property | Value | +|----------|-------| +| Type | Integer | +| Unit | Cycles | +| Default | No limit | + +```yaml +settings: + reserved_cycles_limit: 1000000000000 # 1T cycles +``` + +### wasm_memory_limit + +Maximum heap size for the WASM module. + +| Property | Value | +|----------|-------| +| Type | Integer | +| Unit | Bytes | +| Default | Platform default | + +```yaml +settings: + wasm_memory_limit: 1073741824 # 1GB +``` + +### wasm_memory_threshold + +Memory threshold that triggers low-memory callbacks. + +| Property | Value | +|----------|-------| +| Type | Integer | +| Unit | Bytes | +| Default | None | + +```yaml +settings: + wasm_memory_threshold: 536870912 # 512MB +``` + +### log_visibility + +Controls who can read canister logs. + +| Property | Value | +|----------|-------| +| Type | String | +| Values | `controllers`, `public` | +| Default | `controllers` | + +```yaml +settings: + log_visibility: public +``` + +### environment_variables + +Runtime environment variables accessible to the canister. + +| Property | Value | +|----------|-------| +| Type | Object (string keys, string values) | +| Default | None | + +```yaml +settings: + environment_variables: + API_URL: "https://api.example.com" + DEBUG: "false" + FEATURE_FLAGS: "advanced=true" +``` + +Environment variables allow the same WASM to run with different configurations. + +## Full Example + +```yaml +canisters: + - name: backend + build: + steps: + - type: script + commands: + - cargo build --target wasm32-unknown-unknown --release + - cp target/wasm32-unknown-unknown/release/backend.wasm "$ICP_WASM_OUTPUT_PATH" + settings: + compute_allocation: 5 + memory_allocation: 2147483648 # 2GB + freezing_threshold: 2592000 # 30 days + reserved_cycles_limit: 5000000000000 + wasm_memory_limit: 1073741824 # 1GB + wasm_memory_threshold: 536870912 # 512MB + log_visibility: controllers + environment_variables: + ENV: "production" + API_BASE_URL: "https://api.example.com" +``` + +## Environment Overrides + +Override settings per environment: + +```yaml +canisters: + - name: backend + settings: + compute_allocation: 1 # Default + +environments: + - name: production + network: mainnet + canisters: [backend] + settings: + backend: + compute_allocation: 20 # Production override + freezing_threshold: 7776000 # 90 days + environment_variables: + ENV: "production" +``` + +## CLI Commands + +View settings: + +```bash +icp canister settings show my-canister +``` + +Update settings: + +```bash +icp canister settings update my-canister --compute-allocation 10 +``` + +Sync settings from configuration: + +```bash +icp canister settings sync my-canister +``` + +## See Also + +- [Configuration Reference](configuration.md) — Full icp.yaml schema +- [Managing Environments](../guides/managing-environments.md) — Environment-specific settings +- [CLI Reference](cli.md) — `canister settings` commands diff --git a/docs/cli-reference.md b/docs/reference/cli.md similarity index 100% rename from docs/cli-reference.md rename to docs/reference/cli.md diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md new file mode 100644 index 00000000..0d4f7ea0 --- /dev/null +++ b/docs/reference/configuration.md @@ -0,0 +1,363 @@ +# Configuration Reference + +Complete reference for `icp.yaml` project configuration. + +For conceptual explanation, see [Project Model](../concepts/project-model.md). + +## File Structure + +```yaml +# icp.yaml +canisters: + - # canister definitions or references + +networks: + - # network definitions or references (optional) + +environments: + - # environment definitions (optional) +``` + +## Canisters + +### Inline Definition + +```yaml +canisters: + - name: my-canister + build: + steps: + - type: script + commands: + - echo "Building..." + sync: + steps: + - type: assets + source: www + target: / + settings: + compute_allocation: 5 + init_args: "()" +``` + +### External Reference + +```yaml +canisters: + - path/to/canister.yaml + - canisters/* # Glob pattern + - services/**/*.yaml # Recursive glob +``` + +### Canister Properties + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | string | Yes | Unique canister identifier | +| `build` | object | Yes | Build configuration | +| `sync` | object | No | Post-deployment sync configuration | +| `settings` | object | No | Canister settings | +| `init_args` | string | No | Initialization arguments (Candid or hex) | +| `recipe` | object | No | Recipe reference (alternative to build) | + +## Build Steps + +### Script Step + +Execute shell commands: + +```yaml +build: + steps: + - type: script + commands: + - cargo build --target wasm32-unknown-unknown --release + - cp target/wasm32-unknown-unknown/release/my_canister.wasm "$ICP_WASM_OUTPUT_PATH" +``` + +**Environment variables:** +- `ICP_WASM_OUTPUT_PATH` — Target path for WASM output +- `ICP_PROJECT_ROOT` — Project root directory + +### Pre-built Step + +Use existing WASM: + +```yaml +build: + steps: + - type: pre-built + path: dist/canister.wasm + sha256: abc123... # Optional integrity check +``` + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `path` | string | Yes | Path to WASM file | +| `sha256` | string | No | SHA256 hash for verification | + +### Assets Step + +Bundle static files: + +```yaml +build: + steps: + - type: assets + source: www + target: / + include_patterns: + - "*.html" + - "*.js" + exclude_patterns: + - "*.map" +``` + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `source` | string | Yes | Source directory | +| `target` | string | Yes | Target path in canister | +| `include_patterns` | array | No | Glob patterns to include | +| `exclude_patterns` | array | No | Glob patterns to exclude | + +## Sync Steps + +### Assets Sync + +Upload files to asset canister: + +```yaml +sync: + steps: + - type: assets + source: dist + target: / +``` + +Same properties as assets build step. + +## Recipes + +### Recipe Reference + +```yaml +canisters: + - name: my-canister + recipe: + type: "@dfinity/rust" + sha256: abc123... # Required for remote URLs + configuration: + package: my-crate +``` + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `type` | string | Yes | Recipe source (registry, URL, or local path) | +| `sha256` | string | Conditional | Required for remote URLs | +| `configuration` | object | No | Parameters passed to recipe template | + +### Recipe Type Formats + +```yaml +# Registry (recommended) +type: "@dfinity/rust" +type: "@dfinity/rust@v1.0.0" # With version + +# Local file +type: ./recipes/my-recipe.hb.yaml + +# Remote URL +type: https://example.com/recipe.hb.yaml +``` + +## Networks + +### Managed Network + +```yaml +networks: + - name: local-dev + mode: managed + gateway: + host: 127.0.0.1 + port: 4943 +``` + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | string | Yes | Network identifier | +| `mode` | string | Yes | `managed` | +| `gateway.host` | string | No | Host address (default: 127.0.0.1) | +| `gateway.port` | integer | No | Port number (default: 8000) | + +### Connected Network + +```yaml +networks: + - name: testnet + mode: connected + url: https://testnet.ic0.app + root-key: # For non-mainnet +``` + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | string | Yes | Network identifier | +| `mode` | string | Yes | `connected` | +| `url` | string | Yes | Network endpoint URL | +| `root-key` | string | No | Hex-encoded root key (non-mainnet only) | + +### Docker Network + +```yaml +networks: + - name: docker-local + mode: managed + image: ghcr.io/dfinity/icp-cli-network-launcher + port-mapping: + - "0:4943" +``` + +See [Containerized Networks](../containers.md) for full options. + +## Environments + +```yaml +environments: + - name: staging + network: ic + canisters: + - frontend + - backend + settings: + frontend: + memory_allocation: 2147483648 + backend: + compute_allocation: 10 + environment_variables: + LOG_LEVEL: "info" + init_args: + backend: "(record { mode = \"staging\" })" +``` + +| Property | Type | Required | Description | +|----------|------|----------|-------------| +| `name` | string | Yes | Environment identifier | +| `network` | string | Yes | Network to deploy to | +| `canisters` | array | No | Canisters to include (default: all) | +| `settings` | object | No | Per-canister setting overrides | +| `init_args` | object | No | Per-canister init arg overrides | + +## Canister Settings + +See [Canister Settings Reference](canister-settings.md) for all options. + +```yaml +settings: + compute_allocation: 5 + memory_allocation: 4294967296 + freezing_threshold: 2592000 + reserved_cycles_limit: 1000000000000 + wasm_memory_limit: 1073741824 + wasm_memory_threshold: 536870912 + log_visibility: controllers + environment_variables: + KEY: "value" +``` + +## Init Args + +Candid text format: + +```yaml +init_args: "(record { owner = principal \"aaaaa-aa\" })" +``` + +Hex-encoded bytes: + +```yaml +init_args: "4449444c016d7b0100010203" +``` + +## Implicit Defaults + +### Networks + +| Name | Mode | Description | +|------|------|-------------| +| `local` | managed | `localhost:8000`, can be overridden | +| `ic` | connected | ICP mainnet, cannot be overridden | + +### Environments + +| Name | Network | Canisters | +|------|---------|-----------| +| `local` | local | All | +| `ic` | ic | All | + +## Complete Example + +```yaml +canisters: + - name: frontend + recipe: + type: "@dfinity/assets" + configuration: + source: dist + settings: + memory_allocation: 1073741824 + + - name: backend + build: + steps: + - type: script + commands: + - cargo build --target wasm32-unknown-unknown --release + - cp target/wasm32-unknown-unknown/release/backend.wasm "$ICP_WASM_OUTPUT_PATH" + settings: + compute_allocation: 5 + init_args: "(record { admin = principal \"aaaaa-aa\" })" + +networks: + - name: local + mode: managed + gateway: + port: 9999 + +environments: + - name: staging + network: ic + canisters: [frontend, backend] + settings: + backend: + compute_allocation: 10 + environment_variables: + ENV: "staging" + + - name: production + network: ic + canisters: [frontend, backend] + settings: + frontend: + memory_allocation: 4294967296 + backend: + compute_allocation: 30 + freezing_threshold: 7776000 + environment_variables: + ENV: "production" + init_args: + backend: "(record { admin = principal \"xxxx-xxxx\" })" +``` + +## Schema + +JSON schemas for editor integration are available in [docs/schemas/](../schemas/). + +Configure your editor to use them: + +```yaml +# yaml-language-server: $schema=./docs/schemas/icp-yaml-schema.json +canisters: + - name: my-canister + # ... +``` diff --git a/docs/reference/index.md b/docs/reference/index.md new file mode 100644 index 00000000..543e3568 --- /dev/null +++ b/docs/reference/index.md @@ -0,0 +1,21 @@ +# Reference + +Complete technical specifications for icp-cli. + +## Command Line + +- [CLI Reference](cli.md) — All commands, subcommands, and flags + +## Configuration + +- [Configuration Reference](configuration.md) — Complete icp.yaml schema +- [Canister Settings](canister-settings.md) — All canister settings options + +## Schemas + +JSON schemas for editor integration: + +- [icp.yaml schema](../schemas/icp-yaml-schema.json) +- [canister.yaml schema](../schemas/canister-yaml-schema.json) +- [network.yaml schema](../schemas/network-yaml-schema.json) +- [environment.yaml schema](../schemas/environment-yaml-schema.json) diff --git a/docs/tutorial.md b/docs/tutorial.md new file mode 100644 index 00000000..29d99f0f --- /dev/null +++ b/docs/tutorial.md @@ -0,0 +1,109 @@ +# Tutorial + +Deploy your first canister on the Internet Computer in under 10 minutes. + +## Prerequisites + +Install icp-cli and the toolchain for your canister language. + +### Install icp-cli + +**Via Homebrew (macOS):** + +```bash +brew install dfinity/tap/icp-cli +``` + +**From source:** + +```bash +git clone https://github.com/dfinity/icp-cli.git +cd icp-cli && cargo build --release +export PATH=$(pwd)/target/release:$PATH +``` + +For detailed installation options, see the [Installation Guide](guides/installation.md). + +### Language Toolchains + +Install the toolchain for the language you'll use: + +- **Rust canisters**: [Rust](https://rustup.rs/) and `rustup target add wasm32-unknown-unknown` +- **Motoko canisters**: [mops](https://cli.mops.one/) and `mops toolchain init` + +### Verify Installation + +```bash +icp --version +``` + +## Create a Project + +```bash +icp new my-project +``` + +Select a template when prompted, then enter the project directory: + +```bash +cd my-project +``` + +Your project contains: +- `icp.yaml` — Project configuration +- `src/` — Source code +- `README.md` — Project-specific instructions + +## Start the Local Network + +```bash +icp network start -d +``` + +This starts a local Internet Computer network in the background. + +## Deploy + +```bash +icp deploy +``` + +This single command: +1. **Builds** your source code into WebAssembly (WASM) +2. **Creates** a canister on the local network +3. **Installs** your WASM code + +**Tip:** You can also run `icp build` separately if you want to verify compilation before deploying. + +## Interact with Your Canister + +First, find your canister name: + +```bash +icp canister list +``` + +Then call a method on it (replace `` with your actual canister name): + +```bash +icp canister call greet '("World")' +``` + +You should see: `("Hello, World!")` + +## Stop the Network + +When you're done: + +```bash +icp network stop +``` + +## Next Steps + +You've deployed your first canister. Now: + +- [Core Concepts](concepts/project-model.md) — Understand how icp-cli works +- [Local Development](guides/local-development.md) — Learn the day-to-day workflow + +[Browse all documentation →](index.md) diff --git a/docs/workflows.md b/docs/workflows.md deleted file mode 100644 index 683390ef..00000000 --- a/docs/workflows.md +++ /dev/null @@ -1,168 +0,0 @@ -# Advanced Workflows - -This guide covers advanced usage patterns and workflows for ICP CLI, including multi-environment deployments, CI/CD integration, and complex project management scenarios. - -## Multi-Environment Deployments - -### Environment Strategy - -Set up multiple environments for different stages of your development lifecycle: - -```yaml -# icp.yaml -canisters: - - frontend/canister.yaml - - backend/canister.yaml - - database/canister.yaml - -networks: - - name: local - mode: managed - gateway: - host: 127.0.0.1 - port: 4943 - - - name: testnet - mode: external - gateway: - url: https://testnet.ic0.app - - - name: staging - mode: external - gateway: - url: https://ic0.app - - - name: production - mode: external - gateway: - url: https://ic0.app - -environments: - # Development environment - local testing - - name: dev - network: local - canisters: [frontend, backend, database] - settings: - frontend: - memory_allocation: 1073741824 # 1GB - environment_variables: - NODE_ENV: "development" - API_BASE_URL: "http://localhost:4943" - DEBUG_MODE: "true" - backend: - compute_allocation: 1 - environment_variables: - LOG_LEVEL: "debug" - CACHE_TTL: "60" - - # Testing environment - automated testing - - name: test - network: testnet - canisters: [frontend, backend, database] - settings: - frontend: - memory_allocation: 2147483648 # 2GB - environment_variables: - NODE_ENV: "test" - API_BASE_URL: "https://testnet.ic0.app" - backend: - compute_allocation: 2 - reserved_cycles_limit: 5000000000000 - environment_variables: - LOG_LEVEL: "info" - - # Staging environment - pre-production testing - - name: staging - network: staging - canisters: [frontend, backend, database] - settings: - frontend: - memory_allocation: 4294967296 # 4GB - compute_allocation: 5 - freezing_threshold: 2592000 # 30 days - environment_variables: - NODE_ENV: "staging" - API_BASE_URL: "https://ic0.app" - backend: - compute_allocation: 10 - reserved_cycles_limit: 10000000000000 - environment_variables: - LOG_LEVEL: "warn" - CACHE_TTL: "300" - - # Production environment - live deployment - - name: prod - network: production - canisters: [frontend, backend] # Database separate for prod - settings: - frontend: - memory_allocation: 8589934592 # 8GB - compute_allocation: 20 - freezing_threshold: 7776000 # 90 days - wasm_memory_limit: 4294967296 # 4GB - environment_variables: - NODE_ENV: "production" - API_BASE_URL: "https://ic0.app" - backend: - compute_allocation: 30 - reserved_cycles_limit: 50000000000000 - wasm_memory_limit: 2147483648 # 2GB - environment_variables: - LOG_LEVEL: "error" - CACHE_TTL: "3600" -``` - -### Deployment Commands - -```bash -# Development -icp deploy --environment dev - -# Testing -icp deploy --environment test - -# Staging -icp deploy --environment staging - -# Production -icp deploy --environment prod -``` - -## Recipe Development Workflows - -### Custom Recipe Creation - -**1. Create recipe template:** -```yaml -# recipes/rust-service.hb.yaml -canister: - name: {{configuration.name}} - build: - steps: - - type: script - commands: - - cargo build --package {{configuration.package}} --target wasm32-unknown-unknown {{#if configuration.release}}--release{{/if}} - - mv target/wasm32-unknown-unknown/{{#if configuration.release}}release{{else}}debug{{/if}}/{{configuration.package}}.wasm "$ICP_WASM_OUTPUT_PATH" - - {{#if configuration.settings}} - settings: - {{#each configuration.settings}} - {{@key}}: {{this}} - {{/each}} - {{/if}} -``` - -**2. Use custom recipe:** -```yaml -# services/api/canister.yaml -canister: - recipe: - type: file://../../recipes/rust-service.hb.yaml - configuration: - name: api - package: api-service - release: true - settings: - compute_allocation: 10 - memory_allocation: 4294967296 -``` diff --git a/scripts/generate-cli-docs.sh b/scripts/generate-cli-docs.sh index f302ec5c..176baa5c 100755 --- a/scripts/generate-cli-docs.sh +++ b/scripts/generate-cli-docs.sh @@ -14,9 +14,9 @@ echo "Building the CLI..." cargo build echo "Generating markdown documentation..." -$(git rev-parse --show-toplevel)/target/debug/icp --markdown-help > $(git rev-parse --show-toplevel)/docs/cli-reference.md +$(git rev-parse --show-toplevel)/target/debug/icp --markdown-help > $(git rev-parse --show-toplevel)/docs/reference/cli.md -echo "Documentation generated successfully at docs/cli-reference.md" +echo "Documentation generated successfully at docs/reference/cli.md" echo "" echo "✅ Documentation generation complete!"