diff --git a/AGENT_SKILLS.md b/AGENT_SKILLS.md new file mode 100644 index 0000000..8366ce4 --- /dev/null +++ b/AGENT_SKILLS.md @@ -0,0 +1,135 @@ +# How ICP skills are managed in generated projects + +Every project scaffolded from these templates ships an `AGENTS.md` (and a +`CLAUDE.md` that points to it) with a **self-configuring skills section**. This +document explains what that section does, the choices it offers, and why it is +written the way it is — so a future reader of a project's `AGENTS.md` can tell +where the content came from and why. + +For the broader, tool-agnostic picture of how agents consume ICP skills, see the +developer-docs guide: . + +## What ICP skills are + +ICP skills are tested, frequently-updated instruction files (correct dependency +versions, compiler flags, API signatures, and documented pitfalls) published at +. ICP evolves quickly, so pre-training +knowledge is outdated by definition. The rule agents follow is: **when a skill +and general knowledge disagree, the skill is correct.** + +## The self-configuring `AGENTS.md` + +The skills section of a fresh `AGENTS.md` is delimited by markers: + +``` + + +... + +``` + +While `state:` is `onboarding-needed`, the first agent session runs a one-time +setup: it asks you to choose how this project should use skills, performs the +setup, and then **rewrites everything between the two markers** with a small, +mode-specific block — deleting the onboarding instructions. From then on every +session reads that terse block and behaves accordingly, without asking again. +Only the text between the markers is ever rewritten; anything you add elsewhere +in `AGENTS.md` is left untouched. + +## The three modes + +| Mode | Who it's for | Preconditions | How skills are obtained | +|------|--------------|---------------|-------------------------| +| **autosync** | Claude Code users who want zero-maintenance, always-current skills | bash, `curl`, `jq`, Claude Code | A `SessionStart` hook (`.claude/sync-ic-skills.sh`) mirrors the latest skills into `.claude/skills/` every session | +| **pinned** | Any agent/harness; teams wanting reproducible, version-locked skills | Node / `npx` | `npx skills add dfinity/icskills` records a `skills-lock.json`; skills restored/refreshed via the CLI | +| **on-demand** | Anyone; zero install; the safe default | Network access | Skills fetched fresh from the registry on demand each session | + +`on-demand` is the **recommended default** and the fallback (see below) because it +installs nothing, works with any agent, and is fully reversible. + +### Pinned update policy + +Pinned means "use the version-locked skills" — that is the safe default, so the two +policies only differ in how updates are offered (there is deliberately no silent +auto-update, which a prompt cannot enforce reliably): + +- **manual** — skills change only when the user runs `npx skills update`. +- **ask-first** — before the first task of a session, the agent offers to run + `npx skills update`. If the user declines, or the session is non-interactive + (e.g. CI), it keeps the locked versions and continues — it never blocks the task. + +**An update is refresh + discover.** `npx skills update` only refreshes and prunes +skills already in `skills-lock.json` — it does **not** pull in skills added to the +repo since you pinned ([vercel-labs/skills#591](https://github.com/vercel-labs/skills/issues/591)), +and its stale-skill prune can silently no-op for shorthand sources like +`dfinity/icskills` ([vercel-labs/skills#1376](https://github.com/vercel-labs/skills/issues/1376)). +So whichever policy you pick, an update should also run +`npx skills add dfinity/icskills --list` and offer to add any skills not yet installed +— never `--all`, since pinning is curated. A **renamed** skill surfaces there under its +new name; if `update` left the old name behind, drop it with `npx skills remove `. + +Either way, if the skills are missing they are restored from `skills-lock.json` +with `npx skills experimental_install`. For always-latest without asking, use +`autosync` (Claude Code) or `on-demand` instead — pinned is about control, not +freshness. + +## The two fallbacks (and why they differ) + +If skills aren't present when a session needs them, the recovery path depends on +the mode — because each mode stores skills differently: + +- **autosync → fetch from the registry.** There is no lock file in this mode; the + hook is the source of truth. If the hook hasn't run yet (or `jq` is missing), + the agent fetches skills on demand from + . +- **pinned → `npx skills experimental_install`.** This mode commits a + `skills-lock.json`, so the exact locked versions are restored deterministically + from it. + +## Version control — the maintainer's call + +The templates do **not** touch `.gitignore`; how the skill directories +(`.claude/skills/`, `.agents/skills/`) are tracked is your decision: + +- **Commit them** — reproducible, offline, and reviewable; a natural fit for + `pinned`. Trade-off: with `autosync`, refreshed skills show up as changes to + commit, and `npx skills` may use symlinks that are awkward across platforms. +- **Git-ignore them** — treat them as a managed cache (like `node_modules`); a + natural fit for `autosync` (no churn). They are repopulated by the hook, by + `npx skills experimental_install` (pinned), or by on-demand fetch. +- **Leave it to your harness's default** — also fine; just note that untracked + skill files will otherwise show up in `git status`. + +Whichever you choose, keep the small reproducibility metadata committed: +`skills-lock.json` for `pinned`, and the hook + `.claude/sync-ic-skills.sh` for +`autosync`. That way every mode stays fully recoverable regardless of the +`.gitignore` decision. + +## Non-interactive sessions, and "just start" + +The onboarding never blocks your actual work. If a session can't ask you +(non-interactive/CI) or you'd rather just start coding, the agent uses `on-demand` +for that session only and **does not modify `AGENTS.md`** — leaving the choice +open so a later interactive session can still make it. A choice is persisted only +when you actively make one. + +## Changing your mind later + +To switch modes, reset the marker to re-trigger onboarding: replace the block +between `ic-skills:managed:start` / `end` with a single line: + +``` + +``` + +The next session will walk you through the choice again. (You can also just edit +the configured block by hand if you know the target mode.) + +## A note on reliability + +The self-rewrite is deliberately simple (clear markers, copy-one-block-verbatim) +so a wide range of agents can perform it. It has been validated across simulated +Claude Code / Cursor / Aider sessions. A less capable model could still mis-edit +the block; because `on-demand` is side-effect-free and every mode is recoverable, +the failure modes are benign (an extra prompt, or one session on general +knowledge) rather than destructive. diff --git a/_shared/write-agent-files.rhai b/_shared/write-agent-files.rhai index 69c947f..11eae87 100644 --- a/_shared/write-agent-files.rhai +++ b/_shared/write-agent-files.rhai @@ -1,22 +1,100 @@ -let agents_md = `# AI Agent Instructions - -This is an Internet Computer (ICP) project built with icp-cli. - -Documentation: https://cli.internetcomputer.org/llms.txt - -## Skills - -Tested implementation patterns for ICP development are available as agent skills. -Fetch the skills index and remember each skill's name and description: -https://skills.internetcomputer.org/.well-known/skills/index.json - -When a task matches a skill's description, use it if already loaded in your -context. Otherwise, fetch its content on-demand from the registry: -https://skills.internetcomputer.org/.well-known/skills/{name}/{file} - -Skills contain correct dependency versions, configuration formats, and common pitfalls that prevent build failures. -Always prefer skill guidance over general documentation when both cover the same topic. -`; +// Writes AGENTS.md + CLAUDE.md into every generated icp-cli project (post-hook, +// shared by all sub-templates). AGENTS.md is emitted as an array of double-quoted +// lines joined with "\n": its content has many backticks (markdown code spans) that +// would terminate a Rhai backtick string, and no double quotes, so this needs zero +// escaping. Canonical source and rationale: AGENT_SKILLS.md at the repo root. +let agents_lines = [ + "# AI Agent Instructions", + "", + "This is an Internet Computer (ICP) project built with icp-cli.", + "Documentation: https://cli.internetcomputer.org/llms.txt", + "", + "## Skills", + "", + "", + "", + "", + "ICP evolves quickly. Tested, current implementation patterns are published as", + "agent skills (correct dependency versions, compiler flags, API signatures, pitfalls).", + "Skills are authoritative: when a skill and your general knowledge disagree, the", + "skill is correct. How these options work and why:", + "https://github.com/dfinity/icp-cli-templates/blob/main/AGENT_SKILLS.md", + "", + "This project has not chosen how to use skills yet. Handle setup as follows, and", + "NEVER block the user's actual request on it:", + "", + "- If you CANNOT ask the user (non-interactive session), or the user would rather", + " just start: use `on-demand` for THIS session only (fetch skills on demand — see", + " the on-demand block below), do NOT modify this file, and continue with their", + " request. A later session can still choose.", + "", + "- If you CAN ask: have the user choose ONE option, then perform the matching setup", + " and rewrite this section (STEP 4) so the choice persists:", + " (a) autosync — Claude Code only. Skills auto-update every session.", + " (b) pinned — any agent (needs Node/npx). Skills version-locked via", + " skills-lock.json, restored on demand.", + " (c) on-demand — no install, works anywhere with network. Fetch skills fresh", + " each session. (Recommended default if the user is unsure.)", + " If they chose (b) pinned, also ask how updates should happen: only when the user", + " runs `npx skills update` themselves (manual), or offer to update at the start of", + " each session (ask-first). Either way, an update is refresh + discover: `npx skills", + " update` only refreshes/prunes already-pinned skills, so also run `npx skills add", + " dfinity/icskills --list` and offer to add any not yet installed (never --all).", + "", + "Setup commands:", + " (a) autosync — fetch and follow:", + " https://skills.internetcomputer.org/.well-known/skills/autosync-ic-skills/SKILL.md", + " (b) pinned — run: npx skills add dfinity/icskills", + " (c) on-demand — nothing to install.", + "", + "STEP 4 (only after the user has actively CHOSEN an option) — keep the two", + " `ic-skills:managed:` marker lines exactly as they are, and replace EVERYTHING", + " between them (these instructions included) with the one block below whose", + " `` comment matches the choice. Copy it verbatim; for pinned,", + " pick the block matching the update answer. Do NOT do this if you fell back to", + " on-demand without the user choosing.", + "", + ">>> Blocks to choose from (write exactly one, between the markers):", + "", + "", + "ICP skills auto-update each session via a SessionStart hook (`.claude/sync-ic-skills.sh`)", + "and live in your agent skills directory — you don't need to run anything to refresh them.", + "Skills are authoritative — prefer them over general knowledge for all ICP work.", + "If they are not present (hook hasn't run, or `jq` is missing), fetch them on demand per", + "https://skills.internetcomputer.org/llms.txt instead.", + "How skills are managed here, and why: https://github.com/dfinity/icp-cli-templates/blob/main/AGENT_SKILLS.md", + "", + "", + "ICP skills are version-locked in this repo (skills-lock.json) and live in your agent", + "skills directory. Skills are authoritative — prefer them over general knowledge for all", + "ICP work. Update only when the user runs `npx skills update` — when they do, also check", + "for newly added skills with `npx skills add dfinity/icskills --list` and offer to add any", + "that are missing (remove a renamed skill's old copy with `npx skills remove ` if", + "it lingers). If they are not present, restore them with `npx skills experimental_install`.", + "How skills are managed here, and why: https://github.com/dfinity/icp-cli-templates/blob/main/AGENT_SKILLS.md", + "", + "", + "ICP skills are version-locked in this repo (skills-lock.json) and live in your agent", + "skills directory. Skills are authoritative — prefer them over general knowledge for all", + "ICP work. Before your first task in a new session, offer to run `npx skills update`, then", + "check for newly added skills with `npx skills add dfinity/icskills --list` and offer to add", + "any not yet installed (remove a renamed skill's old copy with `npx skills remove `", + "if it lingers); if the user declines or the session is non-interactive, keep the locked", + "versions and continue — never block. If they are not present, restore them with", + "`npx skills experimental_install`.", + "How skills are managed here, and why: https://github.com/dfinity/icp-cli-templates/blob/main/AGENT_SKILLS.md", + "", + "", + "Fetch the skills index once per session and keep each skill's name, description, and", + "SKILL.md URL: https://skills.internetcomputer.org/.well-known/skills/index.json", + "Before writing ICP code for a task, fetch the matching skill's SKILL.md", + "(https://skills.internetcomputer.org/.well-known/skills/{name}/SKILL.md) and follow it.", + "Skills are authoritative — prefer them over general knowledge.", + "How skills are managed here, and why: https://github.com/dfinity/icp-cli-templates/blob/main/AGENT_SKILLS.md", + "", +]; +let agents_md = ""; +for line in agents_lines { agents_md += line + "\n"; } file::write("AGENTS.md", agents_md); file::write("CLAUDE.md", "Read and follow the instructions in [AGENTS.md](AGENTS.md).\n");