Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .docs-plan/content-authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
When drafting a new docs page:

1. Read the stub page — it contains content brief, source material, and cross-links
2. Read source material from `.sources/`. Stub references use shorthand — resolve them per the mapping in "Source material repos" above (e.g., `Portal: building-apps/foo.mdx` → `.sources/portal/docs/building-apps/foo.mdx`).
> **If source material is unavailable at the expected path:** (1) search `.sources/portal/` for the content under a different path, (2) if truly unavailable, write from the content brief + icskills + your training knowledge, and add `<!-- Source unavailable: [path] — written from content brief -->` so future contributors know to verify.
2. Read source material from `.sources/`. Resolve paths using the "Source material repos" table in AGENTS.md.
> **If source material is unavailable at the expected path:** write from the content brief + icskills + your training knowledge, and add `<!-- Source unavailable: [path] — written from content brief -->` so future contributors know to verify.
3. Read any related icskills skill file from `.sources/icskills/` for accurate canister IDs and code patterns.
4. Write the content:
- Follow the content brief in the stub
Expand Down
4 changes: 0 additions & 4 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
[submodule ".sources/portal"]
path = .sources/portal
url = git@github.com:dfinity/portal.git
branch = master
[submodule ".sources/icp-cli"]
path = .sources/icp-cli
url = git@github.com:dfinity/icp-cli.git
Expand Down
2 changes: 1 addition & 1 deletion .sources/VERSIONS
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Pinned submodule versions (release-pinned repos only)
# -------------------------------------------------------
# Repos that track main/master are NOT listed here — they have no fixed release
# version. Those repos are: portal, examples, icskills, dotskills,
# version. Those repos are: examples, icskills, dotskills,
# icp-cli-recipes, icp-cli-templates, icp-js-sdk-docs.
#
# FORMAT: <submodule> <version label> <7-char hash>
Expand Down
1 change: 0 additions & 1 deletion .sources/portal
Submodule portal deleted from 9d734b
72 changes: 15 additions & 57 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,6 @@ For current release hashes, see `.sources/VERSIONS`.

| Submodule | Repo | Pinned to | What it provides |
|-----------|------|-----------|-----------------|
| `.sources/portal` | `dfinity/portal` | `master` | Old docs content referenced in stub `<!-- Source Material -->` comments |
| `.sources/icp-cli` | `dfinity/icp-cli` | latest release | CLI reference, command syntax verification |
| `.sources/icp-cli-recipes` | `dfinity/icp-cli-recipes` | `main` | Recipe examples for CLI guides |
| `.sources/icp-cli-templates` | `dfinity/icp-cli-templates` | `main` | Project templates for getting-started |
Expand Down Expand Up @@ -236,7 +235,6 @@ git -C .sources/<repo> checkout <commit>
### Rules for agents

- **Always read source material from `.sources/`** — never from local clones, `gh api`, or training data
- **Stub shorthand mapping:** `Portal: building-apps/foo.mdx` → `.sources/portal/docs/building-apps/foo.mdx`
- **Consult relevant repos when writing or reviewing:**
- **Motoko code** → `motoko-core` (API signatures) + `motoko` (compiler: system function names, keywords)
- **Rust code** → `cdk-rs` (`ic-cdk`, `ic-cdk-timers`, management canister types)
Expand All @@ -246,7 +244,6 @@ git -C .sources/<repo> checkout <commit>
- **JavaScript / TypeScript** → `icp-js-sdk-docs` (unzip archives before reading; never guess JS SDK API)
- **Code examples** → `examples` (link to for snippets >30 lines)
- **Do not modify `.sources/`** — read-only. Edits go to the upstream repos.
- **Portal `file=` references:** Resolve `file=../../../../submodules/samples/...` paths via `.sources/examples` instead.

### Bumping submodules

Expand Down Expand Up @@ -279,7 +276,6 @@ EOF

| Submodule | Extra checks on bump |
|---|---|
| `portal` | Follow the full portal checklist in "Synced files from submodules" below |
| `motoko` | **Automated** — `.github/workflows/sync-motoko.yml` opens a PR with the submodule bump, synced docs, and VERSIONS update already committed. Review the content diff and merge. Also check for changed/removed API signatures — grep all Motoko code blocks in docs. |
| `motoko-core` | Check for changed/removed API signatures — grep all Motoko code blocks in docs |
| `cdk-rs` | Check `ic-cdk`, `ic-cdk-timers`, `ic-cdk-macros` API changes — grep all Rust code blocks |
Expand Down Expand Up @@ -326,68 +322,34 @@ Any link of the form `internetcomputer.org/.../ic-interface-spec#<anchor>` or `.
grep -r "{#<anchor>}" docs/references/ic-interface-spec/
```

### Synced files from submodules
### Directly maintained spec files

| Local file | Source | Affects |
|-----------|--------|---------|
| `public/reference/ic.did` | `.sources/portal/docs/references/_attachments/ic.did` | Management canister reference — new/changed methods require updating `docs/references/management-canister.md` |
| `public/references/_attachments/certificates.cddl` | `.sources/portal/docs/references/_attachments/certificates.cddl` | Downloadable CDDL linked from `docs/references/ic-interface-spec/certification.md` |
| `public/references/_attachments/requests.cddl` | `.sources/portal/docs/references/_attachments/requests.cddl` | Downloadable CDDL linked from `docs/references/ic-interface-spec/https-interface.md` |
| `public/references/_attachments/http-gateway.did` | `.sources/portal/docs/references/_attachments/http-gateway.did` | Downloadable Candid interface linked from `docs/references/http-gateway-spec.md` |
| `docs/references/ic-interface-spec/` | `.sources/portal/docs/references/ic-interface-spec.md` | IC interface spec split into 7 focused pages — apply portal diffs by section (see checklist below) |
| `docs/references/http-gateway-spec.md` | `.sources/portal/docs/references/http-gateway-protocol-spec.md` | HTTP Gateway spec — apply portal diff as a patch on every bump |
The following files are no longer synced from an external submodule — they are maintained directly in this repository. Update them manually when the IC team announces a new version of the relevant specification.

**Portal bump checklist (run on every portal bump):**
| Local file | What it is | When to update |
|-----------|-----------|---------------|
| `public/references/ic.did` | Candid interface of the IC management canister | New management canister methods or changed types; update `docs/references/management-canister.md` and affected guides alongside |
| `public/references/_attachments/certificates.cddl` | Certificate CDDL schema (linked from `docs/references/ic-interface-spec/certification.md`) | IC certification spec changes |
| `public/references/_attachments/requests.cddl` | Request CDDL schema (linked from `docs/references/ic-interface-spec/https-interface.md`) | IC HTTPS interface spec changes |
| `public/references/_attachments/http-gateway.did` | HTTP Gateway Candid interface (linked from `docs/references/http-gateway-spec.md`) | HTTP Gateway spec changes |
| `docs/references/ic-interface-spec/` | IC Interface Spec split into 7 focused pages | IC spec version bumps — apply changes to the matching file (see section mapping below) |
| `docs/references/http-gateway-spec.md` | HTTP Gateway Protocol Spec | HTTP Gateway spec version bumps |

**Step 1 — `ic.did` and `_attachments/`:**
1. `diff public/reference/ic.did .sources/portal/docs/references/_attachments/ic.did`
2. If changed: `cp .sources/portal/docs/references/_attachments/ic.did public/reference/ic.did`
3. Review diff for new/changed/removed methods
4. Update `docs/references/management-canister.md` and any affected guides
5. For each of `certificates.cddl`, `requests.cddl`, `http-gateway.did`: `diff public/references/_attachments/<file> .sources/portal/docs/references/_attachments/<file>` — if changed, copy the updated file to `public/references/_attachments/`
**IC Interface Spec — section-to-file mapping:**

**Step 2 — `ic-interface-spec/`:** The spec is now split into 7 files under `docs/references/ic-interface-spec/`. Each file maps to a section of the portal source:

| File | Portal section (## heading) |
| File | IC spec section |
|---|---|
| `index.md` | Introduction, Pervasive concepts, The system state tree |
| `https-interface.md` | HTTPS Interface |
| `canister-interface.md` | Canister module format, Canister interface (System API) |
| `management-canister.md` | The IC management canister, The IC Bitcoin API, The IC Provisional API |
| `certification.md` | Certification, The HTTP Gateway protocol |
| `abstract-behavior.md` | Abstract behavior |
| `changelog.md` | `.sources/portal/docs/references/_attachments/interface-spec-changelog.md` (NOT `ic-interface-spec.md`) |

For every commit in the bump range that touched `docs/references/ic-interface-spec.md`:
1. `git -C .sources/portal show <commit> -- docs/references/ic-interface-spec.md > /tmp/spec.diff`
2. Inspect the diff: identify which section(s) changed
3. Apply the relevant hunks manually to the corresponding file(s) in `docs/references/ic-interface-spec/`
4. Update any cross-file anchor links (`(./other.md#anchor)`) if headings were added or removed
5. Verify new methods/fields are reflected in `docs/references/management-canister.md` if they touch the management canister

For every commit in the bump range that touched `docs/references/_attachments/interface-spec-changelog.md`:
1. `git -C .sources/portal show <commit> -- docs/references/_attachments/interface-spec-changelog.md > /tmp/changelog.diff`
2. Apply the new version entries to `docs/references/ic-interface-spec/changelog.md`

**Step 3 — `http-gateway-spec.md`:** For every commit in the bump range that touched `docs/references/http-gateway-protocol-spec.md`:
1. `git -C .sources/portal show <commit> -- docs/references/http-gateway-protocol-spec.md > /tmp/patch.diff`
2. `patch -F 5 -p1 --input=/tmp/patch.diff docs/references/http-gateway-spec.md`
3. Resolve any rejects manually (see note below on link adaptation)
4. Run `grep -n "ic-interface-spec" docs/references/http-gateway-spec.md` and convert any newly introduced links

**Link adaptation for `http-gateway-spec.md`:** The portal source uses absolute `/references/ic-interface-spec#anchor` URLs. Our file uses relative paths into the split `ic-interface-spec/` directory. After every sync, any link of the form `/references/ic-interface-spec#<anchor>` or `./ic-interface-spec.md#<anchor>` must be converted. Use the anchor-to-file mapping at the bottom of `docs/references/http-gateway-spec.md` as the authoritative guide. If a new anchor appears that is not in the comment, find its file with:
```bash
grep -r "{#<anchor>}" docs/references/ic-interface-spec/
```
| `changelog.md` | IC spec changelog |

**Finding which commits touched which files:**
**Link adaptation for `http-gateway-spec.md`:** If an update introduces absolute `/references/ic-interface-spec#<anchor>` links, convert them to relative paths using the anchor-to-file mapping at the bottom of `docs/references/http-gateway-spec.md`. If a new anchor is not in that comment, find its file with:
```bash
git -C .sources/portal log --oneline <old-ref>..<new-ref> -- docs/references/ic-interface-spec.md
git -C .sources/portal show <commit> -- docs/references/ic-interface-spec.md | grep "^[+-]## " | head -20 # identify which sections changed
git -C .sources/portal log --oneline <old-ref>..<new-ref> -- docs/references/_attachments/interface-spec-changelog.md
git -C .sources/portal log --oneline <old-ref>..<new-ref> -- docs/references/http-gateway-protocol-spec.md
git -C .sources/portal log --oneline <old-ref>..<new-ref> -- docs/references/_attachments/ic.did
git -C .sources/portal log --oneline <old-ref>..<new-ref> -- docs/references/_attachments/certificates.cddl docs/references/_attachments/requests.cddl docs/references/_attachments/http-gateway.did
grep -r "{#<anchor>}" docs/references/ic-interface-spec/
```

## Planning artifacts (`.docs-plan/`)
Expand Down Expand Up @@ -450,10 +412,6 @@ sidebar:
---
```

## Portal tracking

The old portal (`dfinity/portal`) has been replaced by this site. The `.sources/portal` submodule is kept as a read-only reference for spec content (see `ic.did` sync checklist above) but no longer needs active monitoring for content changes.

## Commands

- `npm run dev` — Local dev server
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ docs/ # All documentation (.md only)
└── reference/ # Specs and reference
.sources/ # Pinned upstream source repos (read-only)
├── VERSIONS # Current pinned versions for versioned submodules
└── ... # portal, icp-cli, motoko, cdk-rs, icskills, examples, ...
└── ... # icp-cli, motoko, cdk-rs, icskills, examples, ...
.docs-plan/ # Planning artifacts and authoring workflow
AGENTS.md # Contributor and agent instructions
```
Expand Down
118 changes: 85 additions & 33 deletions docs/references/ic-interface-spec/abstract-behavior.md
Original file line number Diff line number Diff line change
Expand Up @@ -696,10 +696,16 @@ The following predicate describes when an envelope `E` correctly signs the enclo
```
verify_envelope({ content = C }, U, T)
= { p : p is CanisterID } if U = anonymous_id
∧ C.sender_info = null
verify_envelope({ content = C, sender_pubkey = PK, sender_sig = Sig, sender_delegation = DS}, U, T)
= TS if U = mk_self_authenticating_id E.sender_pubkey
= TS if U = mk_self_authenticating_id PK
∧ (PK', TS) = verify_delegations(DS, PK, T, { p : p is CanisterId })
∧ verify_signature PK' Sig ("\x0Aic-request" · hash_of_map(C))
∧ (if PK = canister_signature_pk Signing_canister_id _:
C.sender_info = null
∨ (verify_signature PK C.sender_info.sig ("\x0Eic-sender-info" · C.sender_info.info)
∧ C.sender_info.signer = Signing_canister_id)
else C.sender_info = null)
verify_delegations([], PK, T, TS) = (PK, TS)
verify_delegations([D] · DS, PK, T, TS)
= verify_delegations(DS, D.pubkey, T, TS ∩ delegation_targets(D))
Expand Down Expand Up @@ -762,12 +768,6 @@ Conditions
```html

E.content.canister_id ∈ verify_envelope(E, E.content.sender, S.system_time)
if E.sender_pubkey = canister_signature_pk Signing_canister_id Seed:
if not (E.content.sender_info = null):
verify_signature E.sender_pubkey E.content.sender_info.sig ("\x0Eic-sender-info" · E.content.sender_info.info)
E.content.sender_info.signer = Signing_canister_id
else:
E.content.sender_info = null
if E.content.sender = mk_self_authenticating_id (canister_signature_pk Signing_canister_id Seed):
if E.content.sender_info = null:
Caller_info_data = ""
Expand Down Expand Up @@ -797,7 +797,7 @@ liquid_balance(S, E.content.canister_id) ≥ 0
E.content.arg = candid({canister_id = CanisterId, …})
E.content.sender ∈ S.controllers[CanisterId] ∪ S.subnet_admins[S.canister_subnet[CanisterId]]
E.content.method_name ∈
{ "start_canister", "stop_canister", "uninstall_code", "delete_canister", "canister_status" }
{ "start_canister", "stop_canister", "uninstall_code", "delete_canister", "canister_status", "canister_metrics" }
) ∨ (
E.content.canister_id = ic_principal
E.content.sender ∈ S.subnet_admins[S.canister_subnet[ECID]]
Expand Down Expand Up @@ -867,12 +867,6 @@ Conditions
```html

E.content.canister_id ∈ verify_envelope(E, E.content.sender, S.system_time)
if E.sender_pubkey = canister_signature_pk Signing_canister_id Seed:
if not (E.content.sender_info = null):
verify_signature E.sender_pubkey E.content.sender_info.sig ("\x0Eic-sender-info" · E.content.sender_info.info)
E.content.sender_info.signer = Signing_canister_id
else:
E.content.sender_info = null
|E.content.nonce| <= 32
E.content ∉ dom(S.requests)
S.system_time <= E.content.ingress_expiry
Expand Down Expand Up @@ -1995,12 +1989,6 @@ is_effective_canister_id(E.content, ECID)
S.system_time <= Q.ingress_expiry or Q.sender = anonymous_id
Q.arg = candid(A)
A.canister_id ∈ verify_envelope(E, Q.sender, S.system_time)
if E.sender_pubkey = canister_signature_pk Signing_canister_id Seed:
if not (Q.sender_info = null):
verify_signature E.sender_pubkey Q.sender_info.sig ("\x0Eic-sender-info" · Q.sender_info.info)
Q.sender_info.signer = Signing_canister_id
else:
Q.sender_info = null
Q.sender ∈ S.controllers[A.canister_id] ∪ S.subnet_admins[S.canister_subnet[A.canister_id]]

```
Expand All @@ -2021,6 +2009,82 @@ verify_response(Q, R, Cert) ∧ lookup(["time"], Cert) = Found S.system_time //

```

#### IC Management Canister: Canister metrics

Only the controllers of the given canister or subnet admins can get metrics about it.

```html

S.messages = Older_messages · CallMessage M · Younger_messages
(M.queue = Unordered) or (∀ msg ∈ Older_messages. msg.queue ≠ M.queue)
M.callee = ic_principal
M.method_name = 'canister_metrics'
M.arg = candid(A)
M.caller ∈ S.controllers[A.canister_id] ∪ S.subnet_admins[S.canister_subnet[A.canister_id]]

R = <implementation-specific>

```

State after

```html

S with
messages = Older_messages · Younger_messages ·
ResponseMessage {
origin = M.origin
response = Reply (candid(R))
refunded_cycles = M.transferred_cycles
}

```

The IC method `canister_metrics` can also be invoked via management canister query calls.
They are calls to `/api/v3/canister/<ECID>/query`
with CBOR content `Q` such that `Q.canister_id = ic_principal`.

Submitted request to `/api/v3/canister/<ECID>/query`

```html

E : Envelope

```

Conditions

```html

E.content = CanisterQuery Q
Q.canister_id = ic_principal
Q.method_name = 'canister_metrics'
|Q.nonce| <= 32
is_effective_canister_id(E.content, ECID)
S.system_time <= Q.ingress_expiry or Q.sender = anonymous_id
Q.arg = candid(A)
A.canister_id ∈ verify_envelope(E, Q.sender, S.system_time)
Q.sender ∈ S.controllers[A.canister_id] ∪ S.subnet_admins[S.canister_subnet[A.canister_id]]

```

Query response `R`:

```html

{status: "replied"; reply: {arg: candid(<implementation-specific>)}, signatures: Sigs}

```

where the query `Q`, the response `R`, and a certificate `Cert` that is obtained by requesting the path `/subnet` in a **separate** read state request to `/api/v3/canister/<ECID>/read_state` satisfy the following:

```html

verify_response(Q, R, Cert) ∧ lookup(["time"], Cert) = Found S.system_time // or "recent enough"

```


#### IC Management Canister: Canister information

Every canister can retrieve the canister history, current module hash, and current controllers of every other canister (including itself).
Expand Down Expand Up @@ -4288,12 +4352,6 @@ is_effective_canister_id(E.content, ECID)
S.system_time <= Q.ingress_expiry or Q.sender = anonymous_id
Q.arg = candid(A)
A.canister_id ∈ verify_envelope(E, Q.sender, S.system_time)
if E.sender_pubkey = canister_signature_pk Signing_canister_id Seed:
if not (Q.sender_info = null):
verify_signature E.sender_pubkey Q.sender_info.sig ("\x0Eic-sender-info" · Q.sender_info.info)
Q.sender_info.signer = Signing_canister_id
else:
Q.sender_info = null
(S[A.canister_id].canister_log_visibility = Public)
or
(S[A.canister_id].canister_log_visibility = Controllers and Q.sender in S[A.canister_id].controllers)
Expand Down Expand Up @@ -4511,12 +4569,6 @@ Conditions

E.content = CanisterQuery Q
Q.canister_id ∈ verify_envelope(E, Q.sender, S.system_time)
if E.sender_pubkey = canister_signature_pk Signing_canister_id Seed:
if not (Q.sender_info = null):
verify_signature E.sender_pubkey Q.sender_info.sig ("\x0Eic-sender-info" · Q.sender_info.info)
Q.sender_info.signer = Signing_canister_id
else:
Q.sender_info = null
|Q.nonce| <= 32
is_effective_canister_id(E.content, ECID)
S.system_time <= Q.ingress_expiry or Q.sender = anonymous_id
Expand Down Expand Up @@ -4655,7 +4707,7 @@ Conditions
E.content = ReadState RS
TS = verify_envelope(E, RS.sender, S.system_time)
|E.content.nonce| <= 32
S.system_time <= RS.ingress_expiry
S.system_time <= RS.ingress_expiry or RS.sender = anonymous_id
∀ path ∈ RS.paths. may_read_path_for_subnet(S, RS.sender, path)
∀ (["request_status", Rid] · _) ∈ RS.paths. ∀ R ∈ dom(S.requests). hash_of_map(R) = Rid => R.canister_id ∈ TS

Expand Down
Loading
Loading