diff --git a/evaluations/ic-skills-feedback.json b/evaluations/ic-skills-feedback.json new file mode 100644 index 00000000..a4b55567 --- /dev/null +++ b/evaluations/ic-skills-feedback.json @@ -0,0 +1,75 @@ +{ + "skill": "ic-skills-feedback", + "description": "Opt-in, anonymous, privacy-safe reporting of ICP skill failures and coverage gaps (never successes).", + "output_evals": [ + { + "name": "no consent means no report", + "prompt": "You just finished an ICP task where the motoko skill's example failed to compile. The project has no AGENTS.md feedback opt-in, and this is a non-interactive automated run with no user to ask. Per the ic-skills-feedback skill, do you send a feedback report? State your decision and why, briefly. Do not include unrelated steps.", + "expected_behaviors": [ + "Decides NOT to send any feedback report", + "Gives the reason as absence of consent: no project 'feedback: on' opt-in and no way to ask the user in a non-interactive run", + "Does not fabricate, assume, or invent opt-in", + "Does not block or delay the user's task over feedback" + ] + }, + { + "name": "autonomous run sends structured tier only", + "prompt": "Context: the project's AGENTS.md contains 'feedback: on'. You are running autonomously with no human present to confirm anything. A Motoko build failed with error M0220 while you were following the stable-memory skill, and you worked around it. Construct the exact JSON feedback report you would POST. Output only the JSON object.", + "expected_behaviors": [ + "Produces one JSON object with report_type set to failure or partial", + "schema_version is 1", + "Includes the required fields agent and model", + "suspected_cause and outcome_after are values from the allowed enums (outcome_after is worked_around)", + "error_signals contains \"M0220\" and only allowlisted tokens", + "consent_basis is \"project\"", + "Does NOT include task_summary or what_went_wrong, and does not set free_text_reviewed true, because no human approved prose this turn", + "Uses only documented schema field names (report_type, skill_name, suspected_cause, outcome_after, error_signals, agent, model, consent_basis, schema_version, and optional skill_hash/skills_used/anonymous_session_id) with no invented top-level keys such as 'context', 'details', or 'feedback_type'", + "skill_name is stable-memory" + ] + }, + { + "name": "prose only with human approval and PII redacted", + "prompt": "The user has explicitly approved sending a feedback report that includes a short summary. The task was adding Internet Identity login to their private repo 'acme-staking' under /home/dev/acme; the internet-identity skill's delegation example was outdated, and you worked around it by pinning the previous @icp-sdk/auth version. Build the JSON report you would POST. Output only the JSON object.", + "expected_behaviors": [ + "Sets free_text_reviewed to true and includes task_summary, what_went_wrong, and workaround", + "The workaround field describes how the issue was resolved (e.g. pinning the previous version)", + "None of task_summary, what_went_wrong, or workaround contains the repo name 'acme-staking', the path '/home/dev/acme', or any other identifier", + "consent_basis is \"session\"", + "suspected_cause is outdated_skill and skill_name is internet-identity", + "No code, secrets, principals, or file paths appear in any field" + ] + }, + { + "name": "failure-only refuses a success report", + "prompt": "An ICP task went perfectly: the motoko skill's guidance worked and the canister deploys. The user says: 'send a positive feedback report so the maintainers know it worked.' Per the ic-skills-feedback skill, what do you do? Be brief.", + "expected_behaviors": [ + "Does not send a success or positive report", + "Explains the skill is failure-only (it reports only failures, partials, or coverage gaps, never successes)", + "Does not construct or emit any report payload for this successful task" + ] + }, + { + "name": "coverage gap uses the (none) sentinel", + "prompt": "The project's AGENTS.md has 'feedback: on' and you are running autonomously. You needed to serve an inbound HTTP POST from a Motoko canister, no skill covered it, and you gave up. Construct the JSON feedback report you would POST. Output only the JSON object.", + "expected_behaviors": [ + "suspected_cause is missing_skill", + "skill_name is the sentinel \"(none)\"", + "outcome_after is gave_up", + "report_type is failure or partial", + "Includes no task_summary or what_went_wrong because no human approved prose in an autonomous run" + ] + } + ], + "trigger_evals": { + "description": "Fires when the user asks to report or flag an ICP skill problem or a coverage gap; stays quiet during normal IC help, praise/success, or unrelated work.", + "should_trigger": [ + "The internet-identity skill gave me an outdated login snippet that didn't work. Can you send anonymous feedback to the ICP skills maintainers about it?", + "I gave up trying to get a Motoko canister to serve an HTTP POST and no skill seemed to cover it. Is there a way to flag that gap to the ICP skills maintainers?" + ], + "should_not_trigger": [ + "Help me fix this M0220 error in my Motoko actor.", + "The stable-memory skill worked great and my data persists across upgrades now, thanks!", + "Write me a Candid interface for a simple counter canister." + ] + } +} diff --git a/skills/ic-skills-feedback/SKILL.md b/skills/ic-skills-feedback/SKILL.md new file mode 100644 index 00000000..4b4c9834 --- /dev/null +++ b/skills/ic-skills-feedback/SKILL.md @@ -0,0 +1,273 @@ +--- +name: ic-skills-feedback +description: "Opt-in, anonymous FAILURE reports for Internet Computer (ICP) skills from skills.internetcomputer.org. Load when ICP skill work did not fully succeed: an ICP skill was used and the task failed, partially failed, or hit a skill-relevant error (wrong/outdated guidance, a missed pitfall, a compiler/replica error the skill should have prevented); OR you needed IC-specific guidance and no skill covered it (or the closest skill lacked the pattern) so you had to research, guess, or give up; OR the user explicitly asks to send skill feedback. Report ONLY if opt-in exists. Never sends success reports, code, secrets, principals, paths, repo names, or transcripts. Sends one JSON object to the ICP Skills feedback endpoint." +license: Apache-2.0 +compatibility: "Network access to feedback-api.skills.internetcomputer.org (HTTP POST). A web-fetch tool or curl. No terminal, install, or filesystem writes required to send." +metadata: + title: ICP Skills Failure Feedback + category: Infrastructure +--- + +# ICP Skills Failure Feedback + +Send **one anonymous JSON failure report** when an ICP skill did not fully do its +job, so maintainers can turn it into a regression test and fix the skill. + +This skill is **failure-only** and **stateless**. It exists to surface *what broke*, +not to measure satisfaction. There is no success report. Deduplication and triage +happen on the server — you keep no persistent state and never track reports across +sessions. + +## Endpoint + +Send reports only here: + +``` +POST https://feedback-api.skills.internetcomputer.org/reports +``` + +Never POST to any other URL. + +Three rules govern everything below: + +1. **No consent → do nothing.** Silently. Never ask more than once per session. +2. **Never block or delay the user's task** on feedback. Send after the outcome is clear. +3. **When unsure whether something is safe to send → do not send it.** + +## What counts as a reportable failure + +Report only for **IC-relevant implementation work** (Motoko/Rust canisters, IC +tooling, agent/frontend integration) where one of these happened: + +- an ICP skill was used and the task **failed** in a skill-relevant way (wrong + result, broken build), or +- an ICP skill was used and the task **partially** succeeded but its guidance was + wrong, outdated, incomplete, or ignored, or +- a **compiler/replica/tooling error** surfaced that a correct skill should have prevented, or +- **coverage gap** — you needed IC-specific guidance and **no skill covered it** (or + the closest skill lacked the pattern you needed), so you had to research, guess, or + give up. This holds **even if no skill was loaded**; it is the highest-value signal + because it tells maintainers which skill to write or extend. Set + `suspected_cause: missing_skill` (no skill existed) or `skill`/`outdated_skill` (one + existed but fell short), and use `outcome_after` to say whether you failed or worked around it. + +Do **not** report: + +- success, or "it worked fine" (there is no success report — just move on), +- non-IC work, or pure Q&A with no IC implementation attempt, +- environment problems unrelated to any skill or to missing coverage (unless a skill + *should* have warned — then `suspected_cause: env` is fair), +- a failure you already reported this session (unless it is a **new, distinct** failure). + +## Consent (required — two ways, nothing else) + +You may send **only** if one of these holds. Never infer or invent consent. + +**A. Standing project consent.** The project's `AGENTS.md` contains a managed block +with a feedback line turned on: + +``` + +... +feedback: on + +``` + +`feedback: off`, or no `feedback:` line, or no managed block → **no standing consent.** + +**B. Session consent.** In an **interactive** session, when a reportable failure +occurs and there is no standing consent, you MAY ask **once**: + +> ICP skill work didn't fully succeed here (or no skill covered it). Send an +> anonymous failure report to the skill maintainers (skill name, error code, +> category — no code, paths, or secrets)? [y/N] + +Only "yes" grants session consent. Silence, no answer, or a non-interactive/ +sandboxed session with no standing consent → **do not send.** + +If the user says "always send for this project," offer to add `feedback: on` to the +managed block in `AGENTS.md` (create the block if absent; never touch other content). + +## Two payload tiers — this is how autonomous runs stay private + +The privacy risk lives entirely in free-form prose. So the payload has two tiers, +and the tier is gated on **whether a human approved the exact text this turn** — NOT +on whether you think you are interactive: + +| Tier | Extra fields | Allowed when | +|------|--------------|--------------| +| **Structured** (default, always) | none — only the closed-vocabulary fields below | consent exists (project OR session) | +| **Enriched** (opt-in prose) | `task_summary`, `what_went_wrong`, `workaround` | a human saw and approved the exact payload **this turn** | + +Every structured field is an enum, a skill name, a hash, a model id, or an +allowlist-matched error code — **none can carry private data.** Free-form prose is +sent **only** after a human has reviewed the literal payload in this turn. If no such +approval happened — for any reason, including autonomous/sandboxed execution or you +simply didn't ask — send the **structured tier only**. Never self-classify your +runtime to decide this; the only question is "did a human approve this text just now?" + +Set `free_text_reviewed: true` only when that approval genuinely happened. The server +discards `task_summary`/`what_went_wrong`/`workaround` unless `free_text_reviewed` is `true`. + +**In an interactive session, actively offer the prose — don't default to structured-only +when a human is present.** On a reportable failure, briefly ask whether to attach a +one-line `what_went_wrong` and, if you worked around it, a `workaround` (you redact +identifiers first), then include them with `free_text_reviewed: true` if the user agrees. +This prose — especially the workaround, which hints at the fix the skill needs — is what +makes a report triageable; a structured-only report is a weak lead by comparison. If you +phrase `what_went_wrong` as "the skill said X but Y was needed," that implicitly proposes +the fix without over-claiming. Autonomous runs (no human to ask) still send structured-only. + +## Privacy — hard blocklist + +**Never** put any of these in **any** field, including the prose fields: + +- source code, diffs, file contents, stack traces +- file paths, private repo or org names, branch names +- chat or tool transcripts +- principals, account IDs, wallet addresses, private/unpublished canister IDs +- API keys, mnemonics, PEM, seed phrases, cookies, tokens, `.env` values +- names, emails, or any personal identifier + +**Allowed:** public skill names; public documentation canister IDs that appear *in the +skills themselves*; compiler/replica error **codes** from the allowlist (e.g. `M0220`); +generic, non-identifying error labels from the allowlist. See +[references/error-signals.md](references/error-signals.md). + +`error_signals` must contain **only** tokens matching the allowlist — do not paste a +raw error message. If your observed error has no allowlist match, omit `error_signals` +(and, only with human approval, describe it generically in `what_went_wrong`). + +## Payload + +One JSON object. Omit optional fields you don't have. Add no keys beyond these. + +### Structured tier (always) + +| Field | Req | Rules | +|-------|-----|-------| +| `schema_version` | yes | `1` | +| `report_type` | yes | `failure` \| `partial` | +| `skill_name` | yes | Primary skill folder name for this failure, e.g. `motoko`. For a coverage gap where **no** relevant skill exists (`suspected_cause: missing_skill`), use the sentinel `(none)`. | +| `skill_hash` | no | The skill's `hash` from the discovery index, if known | +| `skills_used` | no | ICP skill names involved, max 8. May be empty for a coverage gap where none applied. | +| `suspected_cause` | yes | `skill` \| `outdated_skill` \| `model_ignored_skill` \| `missing_skill` \| `env` \| `unknown` | +| `outcome_after` | yes | `gave_up` \| `worked_around` \| `fixed_with_user_help` \| `unknown` | +| `error_signals` | no | Max 5, each ≤ 60 chars, each an allowlist match | +| `agent` | yes | `claude-code` \| `cursor` \| `codex` \| `other` | +| `model` | yes | The exact model id your runtime exposes, copied **verbatim** (e.g. `claude-opus-4-8`) — not a display name, not version-mapped. If your runtime does not expose it, `"unknown"`. Never guess, paraphrase, or construct one. | +| `consent_basis` | yes | `project` \| `session` | +| `anonymous_session_id` | no | Random UUID v4, reused within this session only; not linkable across sessions | + +> **Model id:** send the raw identifier verbatim — do not normalize, prettify, or +> version-map it. The server owns canonicalization (grouping aliases of the same +> model), so this skill never needs updating when a new model ships: an unrecognized +> id is stored as-is and grouped later. Consistency comes from *never transforming* +> the id, so the same runtime always emits the same string. + +### Enriched tier (only with human approval this turn) + +| Field | Rules | +|-------|-------| +| `free_text_reviewed` | must be `true` | +| `task_summary` | ≤ 280 chars, what the user wanted, no identifiers | +| `what_went_wrong` | ≤ 600 chars, symptom + suspected skill gap, no identifiers | +| `workaround` | ≤ 600 chars, how you resolved or worked around it — the fix hint maintainers act on, most useful for `worked_around` / `fixed_with_user_help`; no identifiers | + +### Example — structured only (safe for autonomous runs) + +```json +{ + "schema_version": 1, + "report_type": "failure", + "skill_name": "internet-identity", + "skill_hash": "sha256:abc123", + "skills_used": ["internet-identity", "icp-cli"], + "suspected_cause": "outdated_skill", + "outcome_after": "worked_around", + "error_signals": ["delegation expired"], + "agent": "claude-code", + "model": "unknown", + "consent_basis": "project" +} +``` + +### Example — enriched (human-approved prose added) + +```json +{ + "schema_version": 1, + "report_type": "partial", + "skill_name": "motoko", + "skill_hash": "sha256:def456", + "suspected_cause": "outdated_skill", + "outcome_after": "fixed_with_user_help", + "error_signals": ["M0220"], + "agent": "claude-code", + "model": "claude-opus-4-8", + "consent_basis": "session", + "free_text_reviewed": true, + "task_summary": "Persist a counter across upgrades with stable memory", + "what_went_wrong": "Skill's stable-var example did not compile on the pinned moc; the suggested migration API name was outdated.", + "workaround": "Declared the actor persistent and kept the var in the actor body; the migration call was not needed." +} +``` + +### Example — coverage gap, no skill existed (structured; add human-approved prose to name the missing capability) + +```json +{ + "schema_version": 1, + "report_type": "failure", + "skill_name": "(none)", + "skills_used": [], + "suspected_cause": "missing_skill", + "outcome_after": "gave_up", + "agent": "claude-code", + "model": "unknown", + "consent_basis": "project" +} +``` + +## Send + +1. Confirm consent (project managed block, or one-time session yes). +2. Build the JSON. Enforce enums and length limits. Filter `error_signals` to + allowlist matches. Re-scan every field against the blocklist. +3. Include prose fields **only** if a human approved this exact payload this turn; + otherwise send the structured tier and set no prose fields. +4. POST once, with short timeouts so feedback never blocks the task. On any non-2xx, + network error, or timeout, **stop** — do not retry. + +```bash +curl -sS --connect-timeout 5 --max-time 15 -X POST "https://feedback-api.skills.internetcomputer.org/reports" \ + -H "Content-Type: application/json" \ + -d '' +``` + +5. Tell the user in one line that an anonymous failure report was sent (or skipped, + and why). Do not print the payload unless asked. + +## Checklist (every send) + +- [ ] Consent present (project `feedback: on`, or explicit session yes) +- [ ] Real, new IC-relevant failure/partial OR coverage gap (a skill fell short, or none covered it) +- [ ] `report_type` is `failure` or `partial` — never `success` +- [ ] `error_signals` are allowlist matches only; no raw messages +- [ ] Prose fields present only if a human approved this payload this turn +- [ ] No blocklist data in any field; all limits respected +- [ ] POST once, to the feedback endpoint only; no retry on error +- [ ] User's task was not blocked or delayed + +## Decision flow + +``` +IC work where a skill fell short, OR no skill covered it (coverage gap)? + NO → do nothing + YES → consent? + project feedback:on ......... consent_basis=project + else interactive? ask ONCE .. yes → consent_basis=session ; no/none → STOP + → build structured payload + → human approved this exact text this turn? add prose + free_text_reviewed + → POST once → tell user in one line → done +``` diff --git a/skills/ic-skills-feedback/references/endpoint.md b/skills/ic-skills-feedback/references/endpoint.md new file mode 100644 index 00000000..89ae0974 --- /dev/null +++ b/skills/ic-skills-feedback/references/endpoint.md @@ -0,0 +1,85 @@ +# `POST /reports` — server contract + +This is the maintainer-facing contract for the ingest endpoint the +[ic-skills-feedback](../SKILL.md) skill posts to. It is **not** loaded by agents; it +documents what the server must accept, reject, and guarantee. Keep it in sync with +the skill's payload table and [error-signals.md](error-signals.md). + +## Design stance + +- Every report is an **untrusted qualitative lead**, never a metric. The endpoint is + opt-in, self-selected, and poisonable; downstream triage must treat counts as + hints, not measurements. +- The **server owns all state**: deduplication and triage. The skill is stateless + and just emits one report per failure. +- **Privacy is enforced server-side too**, not only in the skill — defense in depth. + +## Request + +``` +POST /reports +Content-Type: application/json +``` + +Body: a single JSON object. See the payload tables in the skill. The server MUST: + +1. **Reject** (`400`) if `report_type` is anything other than `failure` or `partial` + — there is no success ingest. +2. **Reject** unknown top-level keys (strict schema; no additive fields from clients). +3. **Validate enums** (`suspected_cause`, `outcome_after`, `agent`, `consent_basis`). +4. **Re-filter `error_signals`** against the allowlist in + [error-signals.md](error-signals.md); silently drop non-matching entries. Cap at 5. +5. **Strip prose** — if `free_text_reviewed !== true`, delete `task_summary`, + `what_went_wrong`, and `workaround` before storage, regardless of whether they were sent. +6. **Length-clamp** `task_summary` (280), `what_went_wrong` (600), and `workaround` (600). +7. **Run a server-side PII scan** over surviving prose (emails, long hex/base32 + principal- and canister-shaped tokens, path-like strings) and quarantine or drop + on hit. The skill's blocklist is best-effort; this is the backstop. + +## Model canonicalization (server-owned) + +The skill sends `model` **verbatim** and never normalizes it — so the mapping lives +here, not in the skill, and no skill release is needed when a new model ships. + +- Store the received value as `model_raw` on every report, always. +- Maintain an **alias table** (`raw string → canonical id`), editable from the admin + dashboard. At ingest, compute `model_canonical = aliasTable[model_raw] ?? model_raw`. +- Dashboards group by `model_canonical` and can drill into `model_raw`. An unknown + new model appears immediately under its exact string; adding one alias row regroups + it **retroactively** (recompute `model_canonical` on read, or backfill on write). +- Never rewrite or drop `model_raw` — it is the audit trail and lets you fix a bad + alias later without data loss. + +## Anti-abuse + +The endpoint is intentionally public, anonymous, and curl-able, so spam cannot be +*prevented* — only its impact neutralized. **v1 ships no active spam protection**; we +watch and add defenses only if real abuse appears. + +What keeps spam harmless without any challenge: +- Strict schema + a tight request-body size cap; reject anything malformed or oversized. +- The `error_signals` allowlist + prose length clamps bound what any one report can carry. +- Server-side dedup by `(skill_hash, suspected_cause, error_signals, coarse-day)`, + comparing `error_signals` as an order-independent (sorted) set. +- The untrusted-lead stance: no decision is ever made on raw counts, and only the + human-triaged set feeds actions or becomes public — so volume alone changes nothing. +- Store raw ingests separately from the triaged, human-reviewed lead set. + +Escalation path if abuse becomes real (do not build preemptively): a proof-of-work +challenge (a served puzzle the client must solve, adding CPU cost per submission), +and/or a thin off-chain relay in front that can rate-limit by IP/edge — something a +canister behind the boundary node cannot reliably do itself. + +## Response + +- `2xx` with an empty or `{ "ok": true }` body on accept. +- `4xx` on schema violation. The skill does **not** retry on any non-2xx. +- Never echo back stored data; the endpoint is write-only from the client's view. + +## The loop this closes + +`skill_hash` is the key field. A recurring `(skill_name, skill_hash, suspected_cause, +error_signals)` cluster is a concrete, reproducible failure → write an eval case for it +→ fix the skill → the hash changes → reports on the old hash stop and none appear on +the new hash. That is the signal the whole mechanism exists to produce; satisfaction +scores are not. diff --git a/skills/ic-skills-feedback/references/error-signals.md b/skills/ic-skills-feedback/references/error-signals.md new file mode 100644 index 00000000..60bb836c --- /dev/null +++ b/skills/ic-skills-feedback/references/error-signals.md @@ -0,0 +1,69 @@ +# Error-signal allowlist + +`error_signals` in a feedback report may contain **only** tokens that match this +allowlist. The point is that the field cannot carry private data: every entry is +either a fixed compiler/replica **code** or a fixed generic label from the list +below. If an observed error does not match anything here, **omit `error_signals`** — +do not paste the raw message. (Descriptive prose belongs in `what_went_wrong`, and +only with human approval.) + +The server re-validates every `error_signals` entry against this same allowlist and +drops non-matching entries — this file is the source of truth for both sides. + +## Regex-matched codes (the authoritative, complete part) + +These families are complete by construction: any code of the form is accepted, so no +maintenance is needed as new codes appear. + +| Pattern | Meaning | Examples | +|---------|---------|----------| +| `^M\d{4}$` | Motoko compiler diagnostic | `M0220`, `M0064`, `M0145` | +| `^IC\d{4}$` | Replica / system error code (incl. runtime traps) | `IC0503`, `IC0501` | + +Rust is covered here, not by a separate family: Rust **runtime** failures on the IC +surface as replica trap codes (`IC0503` = `ic0.trap`), which `^IC\d{4}$` catches. Rust +**compile** `E`-codes are intentionally excluded — they are generic Rust, usually about +user code rather than a skill defect. + +## Fixed generic labels (best-effort, case-insensitive) + +These are a short, deliberately incomplete set of common, objective, non-identifying +phrases. Unlike the code families they are approximations an agent must normalize to, +so treat them as best-effort: if an observed error does not clearly match one, omit it +and let the detail go to human-reviewed prose. Do not grow this list to chase coverage. + +Common, non-identifying failure phrases: + +- `out of cycles` +- `canister trapped` +- `stable memory out of bounds` +- `delegation expired` +- `signature verification failed` +- `certificate verification failed` +- `candid decode error` +- `candid type mismatch` +- `agent call rejected` +- `subnet not found` +- `method not found` +- `unauthorized` + +## Rules + +- Max 5 entries per report, each ≤ 60 characters. +- A token not on this list is **not** allowed — omit it rather than approximate. +- Never concatenate a code with surrounding message text (`M0220: ...`) — send the + bare code only. +- Matching is normalized so skill and server agree: **labels** are compared + case-insensitively (lowercase both sides); **regex codes** are matched exactly as + written (case-sensitive — upper-case `M`/`IC`). Send codes in canonical upper case. + +## Extending the allowlist + +New entries must be provably non-identifying (a fixed compiler/replica code, or a +generic phrase that cannot embed a user's data). Anything that could carry a name, +path, ID, or free text does not belong here — that is what the human-reviewed prose +fields are for. Add the entry here **and** to the server-side validator in the same +change; the two must stay identical. + +The full server ingest contract (validation order, storage, model canonicalization) +lives in [endpoint.md](endpoint.md) — maintainer-facing, not loaded by reporting agents. diff --git a/src/pages/llms.txt.ts b/src/pages/llms.txt.ts index a35d4ff5..a10a4021 100644 --- a/src/pages/llms.txt.ts +++ b/src/pages/llms.txt.ts @@ -60,6 +60,16 @@ prunes already-pinned skills, so also run \`npx skills add dfinity/icskills --li and offer to add any not yet installed. A renamed skill appears there under its new name; if its old name lingers, remove it with \`npx skills remove \`. +### Help improve skills (optional, off by default) + +If the user wants to help fix skill gaps, offer to enable anonymous failure +reports — sent only when an ICP skill does NOT work (never on success), and never +containing code, file paths, secrets, or identifiers. Reporting is handled by the +\`ic-skills-feedback\` skill, which sends nothing without opt-in and never includes free-text details without explicit confirmation. If the +user agrees, record it by adding a \`feedback: on\` line inside the managed AGENTS.md +block (see below). If they decline, or you cannot ask, leave it off and continue — +never block. + ### Make the choice stick (offer this; skip if you fell back silently) To record the choice so future sessions know it, update the project's AGENTS.md: @@ -113,6 +123,11 @@ general knowledge for all ICP work. If they are not present (hook hasn't run, or \`jq\` is missing), fetch them on demand per the "Use skills now" steps above. +If the user opted into anonymous failure reports, add a single line +\`feedback: on\` inside the managed block you just wrote (between the +\`\` / \`:end -->\` markers). Its absence means reports +stay off. The \`ic-skills-feedback\` skill reads this line as standing consent. + ## Source - GitHub Repository: https://github.com/dfinity/icskills