From f98f9ecfea4af7aef8fe09956688d5053e3e2b0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Tani=C3=A7a?= Date: Fri, 11 Sep 2026 10:51:03 +0100 Subject: [PATCH] fix: shorten skill descriptions over the 1024-character operator limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pi coding agent (v0.85.1) warns about any skill whose description exceeds 1024 characters at startup — the base performance skill (1078 chars) triggers "[Skill conflicts] description exceeds 1024 characters (1078)" on every launch. The skill still loads (pi treats this as a validation warning, not a rejection), but the warning names a file we ship, so keep our descriptions within the limit. - Trim the performance skill description from 1078 to 949 characters, keeping every trigger cue (slow/laggy/janky surfaces, re-renders, memoization, FlashList, Reanimated, TTI, bundle size, cpuprofile, render-regression tests, and the exclusions). - Trim the swaps-cpu-profile-audit description from 1411 to 893 characters, which also tripped the warning in pi. - Lower DESCRIPTION_MAX to 1024, the strictest operator's validation limit, so the linter blocks descriptions that trip operator warnings, and update the schema comment, README, CONTRIBUTING, and skill template to state the new number and cite the operator. Cite-the-operator evidence requested by the schema comment: pi coding agent v0.85.1, docs/skills.md — Validation section: over-limit descriptions "produce warnings but still load the skill". --- .github/SKILL_TEMPLATE.md | 2 +- CONTRIBUTING.md | 2 +- README.md | 6 ++-- .../performance/skills/performance/skill.md | 2 +- .../skills/swaps-cpu-profile-audit/skill.md | 31 +++++++------------ test/lint-skill-entry.test.mjs | 9 +++--- tools/skill-schema.mjs | 14 +++++---- 7 files changed, 32 insertions(+), 34 deletions(-) diff --git a/.github/SKILL_TEMPLATE.md b/.github/SKILL_TEMPLATE.md index 0437c846..76f8726d 100644 --- a/.github/SKILL_TEMPLATE.md +++ b/.github/SKILL_TEMPLATE.md @@ -12,7 +12,7 @@ name: example-skill description: >- One or two sentences: what the skill does, plus when_to_use cues (e.g. "Use when asked to …, or for …"). Keep the full description - within 1,536 characters. + within 1,024 characters. maturity: stable --- diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d2616a98..45b7d51a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -170,7 +170,7 @@ Your `skill.md` should include YAML frontmatter plus body content: ```yaml --- name: -description: <≤1,536 chars including when_to_use cues> +description: <≤1,024 chars including when_to_use cues> maturity: stable # experimental | stable | deprecated --- ``` diff --git a/README.md b/README.md index c1608837..150f11c2 100644 --- a/README.md +++ b/README.md @@ -377,7 +377,7 @@ domains// ```yaml --- name: -description: <≤1,536 chars including when_to_use cues> +description: <≤1,024 chars including when_to_use cues> maturity: stable # experimental | stable | deprecated (default stable) --- ``` @@ -386,7 +386,9 @@ Extra metadata blocks (e.g. OpenClaw-style `metadata:` with emoji and homepage) are preserved through install — only `name`, `description`, `maturity`, `base`, and `scope` are read by the CLI. -The 1,536-character ceiling is a repo budget rather than an operator limit — the +The 1,024-character ceiling tracks the strictest operator rather than an opinion +about ideal length — descriptions well over 1,024 install and load in Claude Code, +but the pi coding agent warns about any description over 1,024 characters at startup. The description is always-on context for every installed skill, so it is capped deliberately. It is enforced by `yarn audit:skills` from [`tools/skill-schema.mjs`](tools/skill-schema.mjs), which is the source of truth. diff --git a/domains/performance/skills/performance/skill.md b/domains/performance/skills/performance/skill.md index 26d5b51f..9d80e329 100644 --- a/domains/performance/skills/performance/skill.md +++ b/domains/performance/skills/performance/skill.md @@ -1,5 +1,5 @@ --- name: performance -description: Use for any performance question about the MetaMask Mobile React Native app, at any stage. Trigger when: a screen, list, or interaction feels slow, laggy, or janky (account/network switching, scrolling, typing, FPS drops); planning a feature with real-time/websocket data, frequent updates, or large lists and wanting to avoid perf pitfalls before building; reviewing or auditing PRs/code for excessive re-renders, broken selector memoization, Context providers, hook deps, or bundle bloat; making the app faster for power users with many accounts/assets; measuring time-to-interactive, render counts, or FPS and surfacing them in Sentry; analyzing a captured `.cpuprofile` / React Native Release Profiler trace (e.g. a `sampling-profiler-trace*.cpuprofile`) to find why a flow is slow; or adding render-regression tests so CI catches slowdowns. Covers re-renders, reselect memoization, FlashList, Reanimated, TTI, bundle size, trace() instrumentation, and Release Profiler CPU-profile analysis. Not for correctness bugs, styling/spacing, Solidity gas, or the browser extension. +description: Use for any performance question about the MetaMask Mobile React Native app. Trigger when: a screen, list, or interaction feels slow, laggy, or janky (account/network switching, scrolling, typing, FPS drops); planning a feature with real-time/websocket data, frequent updates, or large lists; reviewing or auditing PRs/code for excessive re-renders, broken selector memoization, Context providers, hook deps, or bundle bloat; making the app faster for power users with many accounts/assets; measuring time-to-interactive, render counts, or FPS and surfacing them in Sentry; analyzing a captured `.cpuprofile` / React Native Release Profiler trace to find why a flow is slow; or adding render-regression tests so CI catches slowdowns. Covers re-renders, reselect memoization, FlashList, Reanimated, TTI, bundle size, trace() instrumentation, and CPU-profile analysis. Not for correctness bugs, styling/spacing, Solidity gas, or the browser extension. base: true --- diff --git a/domains/swaps/skills/swaps-cpu-profile-audit/skill.md b/domains/swaps/skills/swaps-cpu-profile-audit/skill.md index d5687ec6..f3b0d42a 100644 --- a/domains/swaps/skills/swaps-cpu-profile-audit/skill.md +++ b/domains/swaps/skills/swaps-cpu-profile-audit/skill.md @@ -2,25 +2,18 @@ name: swaps-cpu-profile-audit description: >- Parse an already-recorded Hermes / React Native Release Profiler - `.cpuprofile` (ideally symbolicated with source maps) and audit it for slow - frames on the swaps/bridge screen and the modals or subpages it opens — - quote select screen, post-trade modal, batch sell, asset picker/token - selector. Use when a user hands you a `.cpuprofile` file (e.g. a - `sampling-profiler-trace*.cpuprofile`, or its already-converted - `*-converted.json`) recorded per `docs/readme/release-build-profiler.md` and - asks to audit, analyze, explain, or find why the swaps/bridge flow is slow - based on that trace. This is an offline, file-based analysis — no simulator, - device, Metro, or `mm` session is required, unlike `swaps-perf-audit` (which - measures live render counts on a running simulator). The audit accounts for - ALL time in the capture, not just swaps-owned code: non-swaps frames that - ran while the user sat on a swaps screen (navigation, redux, design system, - polling controllers, React internals) are reported too, each labelled with - whether the swaps team owns it and how it relates to the swaps call stacks. - The report always leads with a timing table (capture metrics + by-area self - time with an ownership column) and a short outcome line, and only adds a - probable-cause/fix table when there is an actual issue — deep fixes are - proposed for swaps-owned rows, while non-owned rows are named and routed. - MetaMask Mobile only. + `.cpuprofile` and audit it for slow frames on the swaps/bridge screen and + its modals (quote select, post-trade, batch sell, asset picker). Use when a + user hands you a `.cpuprofile` (e.g. `sampling-profiler-trace*.cpuprofile`) + and asks to audit, analyze, or explain why the swaps/bridge flow is slow. + Offline, file-based analysis — no simulator, device, Metro, or `mm` session + required, unlike `swaps-perf-audit` (live render counts on a running + simulator). Accounts for ALL time in the capture, not just swaps-owned code: + non-swaps frames (navigation, redux, design system, polling controllers, + React internals) are reported with swaps ownership and relation to the swaps + call stacks. The report leads with a timing table and a short outcome line; + a probable-cause/fix table appears only for actual issues. MetaMask Mobile + only. maturity: stable --- diff --git a/test/lint-skill-entry.test.mjs b/test/lint-skill-entry.test.mjs index d9a7de66..cda3148e 100644 --- a/test/lint-skill-entry.test.mjs +++ b/test/lint-skill-entry.test.mjs @@ -179,10 +179,11 @@ describe('schema tracks the installer', () => { // The workflow invokes the linter WITH changed-file arguments. Every test above runs the // no-argument full-audit branch, so the branch CI actually depends on had no coverage — // which is how malformed paths reached main. These mirror the CI invocation. -// 1,536 is a repo budget, not an operator limit — no observed operator rejects or -// truncates a longer description, and several over 1,024 install and load today. The -// check exists to bound always-on context, so what matters is that the number the docs -// state and the number enforced are the same one. +// 1,024 tracks the strictest operator observed so far: descriptions well over 1,024 +// install and load in Claude Code, and the pi coding agent loads longer ones too but +// warns about them at startup. The check exists to bound always-on context, so what +// matters is that the +// number the docs state and the number enforced are the same one. describe('description budget', () => { test('the enforced ceiling is the one the docs state', () => { const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); diff --git a/tools/skill-schema.mjs b/tools/skill-schema.mjs index 5ce8b65b..2a21dc58 100644 --- a/tools/skill-schema.mjs +++ b/tools/skill-schema.mjs @@ -48,12 +48,14 @@ export const KNOWN_REPOS = ['metamask-extension', 'metamask-mobile', 'core']; // per-skill always-on cost, and the only part of a skill that carries its own trigger // cues — cutting it makes the skill less likely to be selected when it is relevant. // -// This is a REPO BUDGET, not an operator limit. No operator observed here rejects or -// truncates a longer one: `tools/install` emits the value verbatim, and descriptions -// well over 1024 characters install and load in Claude Code today. Treat a lower number -// as a deliberate budget decision, and cite the operator and version before claiming any -// figure is externally imposed. -export const DESCRIPTION_MAX = 1536; +// This number tracks the strictest operator observed so far, not a judgement about the +// ideal length: `tools/install` emits the value verbatim, and descriptions well over +// 1024 characters install and load in Claude Code today. The pi coding agent (v0.85.1, +// docs/skills.md) also loads longer descriptions but flags any over 1024 characters +// with a "[Skill conflicts]" warning at startup — so 1024 is the largest value that +// trips no operator's validation. Raise it only with evidence that no operator warns +// below it. +export const DESCRIPTION_MAX = 1024; // A base skill installs for every engineer, so its description is always-on // context — and a description too thin to match anything is the failure mode