Serve skill:// resources from a reviewed static bundle - #164
Conversation
The served resource surface no longer retrieves anything over the network: the 24 official IC skills are compiled into the binary from crates/imcp2-core/static/skills/ (bundled 2026-08-28 from the public skills registry; provenance, curation notes, and the refresh procedure are in the bundle's README), and resources/list + resources/read serve exactly that bundle. The live skills catalogue stays behind as library code for the unserved protocol tools, so the hosted and local binaries no longer construct it — and no longer read SKILLS_URL or contact skills.internetcomputer.org at all. Docs follow the binary: the README's skills section describes the reviewed, versioned bundle; the privacy policy (draft and served page) drops the skills host from the disclosed recipients and bumps the effective date; the submission doc's third-party list and prompt-injection acknowledgment now state that no instructions are retrieved over the network. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LvwAVXfx5kLNc4SqKXkavk
There was a problem hiding this comment.
Pull request overview
Moves served skill:// resources from live registry fetches to a reviewed bundle compiled into both binaries.
Changes:
- Adds 24 bundled IC skill documents.
- Serves bundled resources without runtime registry access.
- Updates constructors, privacy disclosures, and submission documentation.
Reviewed changes
Copilot reviewed 34 out of 34 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
README.md |
Documents static skill delivery. |
src/lib.rs |
Removes hosted live-catalog construction. |
src/assets/privacy-policy.html |
Updates effective date and recipients. |
docs/icp-mcp-privacy-policy-draft.md |
Updates draft privacy disclosures. |
docs/anthropic-directory-submission.md |
Updates directory attestations. |
crates/imcp2-local/src/main.rs |
Removes local live-catalog construction. |
crates/imcp2-local/src/server.rs |
Updates local test construction. |
crates/imcp2-core/src/tools.rs |
Serves bundled skill resources. |
crates/imcp2-core/src/skills.rs |
Defines bundle lookup and validation. |
crates/imcp2-core/static/skills/README.md |
Records bundle provenance and curation. |
static/skills/agent-web-identity.md |
Bundles web identity guidance. |
static/skills/caffeine-app.md |
Bundles Caffeine app guidance. |
static/skills/canhelp.md |
Bundles canister help guidance. |
static/skills/canister-security.md |
Bundles security guidance. |
static/skills/certified-variables.md |
Bundles certification guidance. |
static/skills/cloud-engine-canisters.md |
Bundles cloud-engine guidance. |
static/skills/custom-domains.md |
Bundles custom-domain guidance. |
static/skills/cycles-management.md |
Bundles cycles guidance. |
static/skills/deploy-to-cloud-engine.md |
Bundles cloud deployment guidance. |
static/skills/encrypted-maps.md |
Bundles encrypted storage guidance. |
static/skills/evm-rpc.md |
Bundles EVM RPC guidance. |
static/skills/https-outcalls.md |
Bundles HTTPS outcall guidance. |
static/skills/ic-dashboard.md |
Bundles dashboard API guidance. |
static/skills/icp-cli.md |
Bundles CLI guidance. |
static/skills/internet-identity.md |
Bundles authentication guidance. |
static/skills/migrating-motoko-actors.md |
Bundles migration guidance. |
static/skills/mops-cli.md |
Bundles Mops guidance. |
static/skills/multi-canister.md |
Bundles multi-canister guidance. |
static/skills/service-discoverability.md |
Bundles discoverability guidance. |
static/skills/stable-memory.md |
Bundles stable-memory guidance. |
static/skills/static-site.md |
Bundles static-site guidance. |
static/skills/troubleshooting-motoko-migrations.md |
Bundles migration troubleshooting. |
static/skills/vetkeys.md |
Bundles vetKeys guidance. |
static/skills/writing-motoko.md |
Bundles Motoko guidance. |
Suppressed comments (3)
crates/imcp2-core/static/skills/caffeine-app.md:434
- This second live-registry instruction reintroduces dynamic behavioral content despite the PR's static-review guarantee. Direct the client to the bundled
skill://writing-motokoresource.
8. **Writing Motoko without the `writing-motoko` skill.** Modern Caffeine Motoko uses
`mo:core`, persistent actors, and specific patterns. Guessing produces compiler
errors. Load <https://skills.internetcomputer.org/skills/writing-motoko/SKILL.md> first.
crates/imcp2-core/static/skills/caffeine-app.md:455
- This third live URL again tells the agent to bypass the reviewed bundle. Keep the required companion reference entirely within
skill://.
- **`writing-motoko`** — REQUIRED companion. Authoritative for all backend Motoko code:
<https://skills.internetcomputer.org/skills/writing-motoko/SKILL.md>. Always load it before
editing `src/backend/main.mo`.
crates/imcp2-core/static/skills/stable-memory.md:340
- The summary repeats the incorrect claim that
Bound::Unboundedprevents schema-compatibility breakage. It prevents size-bound failures, but existing CBOR still fails to deserialize after adding a required field without a default or migration.
- Implement `Storable` for custom types: define `BOUND`, `to_bytes`, `into_bytes`, and `from_bytes`. Use `ciborium::into_writer`/`ciborium::from_reader` for CBOR serialization (compact, fast). Prefer `Bound::Unbounded` -- it avoids backwards compatibility breakage when adding new fields. `Bound::Bounded` exists but is not recommended because exceeding `max_size` after a schema change breaks deserialization
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Review found the bundle was not self-contained, which left the retrieval it removes still reachable from inside a served document: - Three lines of caffeine-app told the agent to load writing-motoko's SKILL.md from the registry over HTTP. A bundled instruction to fetch instructions defeats the bundle; they now point at the skill://writing-motoko resource. - Eleven companion documents that skills link to (the Motoko API reference, the asset-canister migration notes, and the rest) were not bundled, so every "see references/x.md" link was a dead end. They are bundled now, served as skill://<name>/references/<file>, and the links inside the bundled documents point at those URIs. - canhelp is dropped. It is a slash-command skill whose steps run ./scripts/*.sh from a local checkout, which no MCP client has, and its job is what get_canister_candid already does here. read_resource and list_resources now share one lookup (skills::bundled_skill_document), so what is served cannot drift from what is advertised. A test walks every bundled document and asserts the bundle is closed under its own links: nothing points at the registry, every skill:// link resolves, and every listed URI is readable. The bundle README records the two mechanical edits to the mirrored text (the link rewrite and the caffeine-app loads) so a refresh re-applies them, and states that content corrections belong upstream. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LvwAVXfx5kLNc4SqKXkavk
|
CI is red on The failing check is That is a live-network test against the IC dashboard API, which is down: a direct request to the same URL returns HTTP 524 and then times out outright on three consecutive attempts from here. The There is no fix to port — the service is the fix — and I am not touching the test: making a live-network assertion pass while the network is down would mean weakening it, which is not something to do for an outage, and certainly not in this PR. The re-run is held until the dashboard answers again; a check-in is scheduled to do that and report back here only if the result is anything other than green. Generated by Claude Code |
The first pass extracted companion references by markdown-link syntax, which missed the ones written in prose — nine documents that skills tell the agent to read (icp-cli's four guides, vetkeys' ibe and bls-signing, encrypted-maps' metadata, and the binding-generation guide two other skills cite) were named but not bundled, so following that guidance still ended in resource_not_found. All of them are bundled now, and every `references/<file>.md` mention is rewritten to its `skill://` URI in prose as well as in links, inside the companions as well as the skills. The two cross-skill citations point at icp-cli's copy, which is where they said to look. The closure test now flags a bare relative mention as well as an unresolvable `skill://` link, which is what would have caught this: it was the mention form, not the link target, that the first pass got wrong. Three handoffs sent the agent to skills this bundle does not carry — cycles-management and internet-identity to wallet-integration, evm-rpc to canhelp. They now say the topic is outside the bundle, or name the tool that does the job. The README's closure claim is narrowed to what the bundle actually guarantees: references between bundled documents resolve to served resources. Ordinary external links (crates.io, GitHub, the docs site) stay as they are, and saying otherwise overstated the property. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LvwAVXfx5kLNc4SqKXkavk
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 51 out of 51 changed files in this pull request and generated 2 comments.
Suppressed comments (1)
crates/imcp2-core/src/skills.rs:36
- The current PR description says this table bundles 24 official skills, but it contains 23 entries (with
canhelpdeliberately excluded). Update the PR description to 23 skills plus 18 companion documents so the reviewed release inventory is accurate.
pub const BUNDLED_SKILLS: &[(&str, &str, &str)] = &[
The nested link in static-site's legacy-asset-canister companion was rewritten in the first pass and then silently reverted: the second pass re-fetched that file from the registry to pick up the companions the first pass had missed, overwriting the edit. The closure test did not notice, because it scanned for `references/` mentions and this link is a plain sibling target with no such segment. Both halves are fixed: the link points at its bundled URI again, and the test now also requires every markdown target ending in `.md` to be an absolute URI, which is the check that would have caught the revert. The bundle README no longer offers icp_lookup_canister_info_by_id as something available here — it lives on the unserved protocol router, so naming it alongside get_canister_candid described a tool no client of this bundle can call. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LvwAVXfx5kLNc4SqKXkavk
The bundle test rebuilds the skill:// URIs from the same tables the handler serves them from, so it stays green if list_resources omits an entry or read_resource is wired wrong — the central path of this PR was the one thing not covered. The local crate already round-trips a real client over an in-process duplex pipe for the tool surface; the resource surface now goes through the same harness. It lists resources, reads every advertised skill:// URI and asserts each arrives non-empty, checks that a companion is reachable at the child URI its parent's links point at, and asserts that an unknown skill and an unknown companion of a real skill both come back as resource_not_found rather than a panic, a disconnect, or an empty document. No network: every resource is compiled in. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LvwAVXfx5kLNc4SqKXkavk
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 51 out of 51 changed files in this pull request and generated no new comments.
Suppressed comments (1)
crates/imcp2-core/src/skills.rs:455
- The closure check still misses bare references to a companion's parent
SKILL.md, even though that filename is not a readable MCP URI. Current examples includereferences/icp-cli/canister-env-vars.md:3,binding-generation.md:91,references/vetkeys/ibe.md:158, and both static-site companions. Rewrite these to their parentskill://<name>URI and extend this check to reject bareSKILL.mdmentions; otherwise the documented guarantee that internal references resolve to served resources is not true.
// The same holds for a markdown link straight at a sibling file,
// which carries no `references/` segment to catch it by: inside a
// companion, `](migrating-from-asset-canister.md)` addresses a
// document the client cannot open either. Every markdown target
// ending in `.md` must be an absolute URI.
Two conflicts, both from #164 touching the privacy policy this branch deletes: - src/assets/privacy-policy.html: modified on main (the third-party recipients list drops skills.internetcomputer.org — skills are now served from the reviewed bundle compiled into the binary, so no network fetch to disclose), deleted here. The deletion stands; the content change is ported to the page's one home in dfinity/internetcomputer-org (the #77 re-sync branch), where the policy now lives. - docs/anthropic-directory-submission.md: both sides rewrote the "Publication venue" paragraph. Kept this branch's new-home framing, folding in main's note about what the refreshed text carries (the identifier-linkability wording and the updated third-party list). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xpg83AWtkQo34jbMxpX8WB
main now ships a service-discoverability skill (#164's static bundle): the deploy-time recipe for generating /.well-known/ic-architecture with real per-environment canister IDs. That is exactly what someone who has just hit this refusal needs, and the person reading it is sometimes the one who can ship the manifest. So the refusal names skill://service-discoverability alongside the published guide, mirroring how compliance.rs points at skill://icp-cli and skill://cycles-management for the operations it declines. "Publish a manifest" is a much weaker handoff than the recipe for generating one. Also merges main, which moved under this branch while it was open. No textual conflict, but main's series touched tools.rs, IcTools::new and the README, so the merge was verified rather than assumed: it builds and the full suite passes (264 tests), and clippy is unchanged at 11. The skill and this gate agree, which is worth stating: the skill tells an app how to publish the manifest, and the gate makes publishing it the act that permits a write. Claude-Session: https://claude.ai/code/session_01JarhapgjytMcVSCW7d8sqB Co-authored-by: Claude <noreply@anthropic.com>
Summary
The served
skill://resources are now compiled into the binary from a reviewed, versioned bundle instead of being fetched live fromskills.internetcomputer.orgat request time. Directory review treats dynamically retrieved behavioral instructions as a rejection trigger; a static bundle means what an agent reads is exactly what was reviewed at release, and the served binary no longer retrieves any instructions over the network.Related issues
None — follow-up in the directory-submission series (after #158/#161).
Changes
crates/imcp2-core/static/skills/— 23 official IC skills (SKILL.mdeach) bundled 2026-08-28 from the public skills registry, plus 18 companion documents underreferences/<skill>/<file>, served asskill://<skill>/references/<file>. The bundle README documents provenance, the curation (what was excluded and why), the local edits applied to the mirrored text, and the refresh procedure.skills.rs—BUNDLED_SKILLSandBUNDLED_SKILL_REFERENCEStables (include_str!), withbundled_skill_document()resolving askill://path for bothlist_resourcesandread_resource, so the served set cannot drift from the advertised set. Two tests: the bundle is well-formed, and it is closed under its own references — no document points at the registry, everyskill://link resolves, no companion is named by a bare relative path, and every listed URI is readable.tools.rs—IcTools(the served composition) drops itsSkillsCatalog; resources come from the bundle. The liveSkillsCatalogremains library code for the unservedIcProtocolTools, so an embedder who wants live skills still has the machinery.src/lib.rs,crates/imcp2-local/— neither binary constructs the live catalogue any more, so neither readsSKILLS_URLnor contactsskills.internetcomputer.org.Local edits to the mirrored text
The files are verbatim apart from three mechanical edits, recorded in the bundle README and re-applied on refresh: companion references rewritten to their
skill://URIs; three lines ofcaffeine-appthat told the agent to load another skill'sSKILL.mdover HTTP pointed atskill://writing-motoko; and handoffs to skills this bundle does not carry (wallet-integration,canhelp) neutralized. Content itself is not edited — corrections belong upstream in the registry, and four defects found during review were forwarded there.Testing
cargo build --locked --all-targetscargo test --locked --all-targets— green exceptdiscover::tests::search_finds_ckusdc_and_lookup_identifies_it, a live-network test failing because the IC dashboard API is down (see the comment below); unrelated to this diff and failing identically on other branchescargo clippy --all-targets— unchanged 10-warning baseline (this repo is not rustfmt-clean; no repo-widecargo fmt, matching prior PRs)npm test --prefix monitoring/mcp-status(dashboard unchanged)Checklist