Source profileQuality 92/100

brianwestphal/glassbox/.claude/skills/kerf-app/SKILL.md

kerf-app

Build UIs in the kerf reactive framework (https://github.com/brianwestphal/kerf). Use this skill whenever the user is writing or modifying code that imports `kerfjs`, asks to add a feature to a kerf app, or asks "how do I do X in kerf?". Use it proactively the moment you spot a kerf import in the file you're editing.

Source repository stars
34
Declared platforms
0
Static risk flags
0
Last source update
2026-08-26
Source checked
2026-08-28

Decision brief

What it does: where it fits

Drop this file into your /.claude/skills/kerf-app/SKILL.md (or your project's .claude/skills/kerf-app/SKILL.md) so Claude Code activates it whenever you work on a kerf app.

Best for

    Not for

    • Tasks that require unconfirmed production actions or broad system permissions.
    • Environments where the pinned source and install steps cannot be inspected.

    Compatibility matrix

    Platform support, with evidence labels

    PlatformStatusEvidenceWhat to check
    CodexNot declaredNo explicit evidencePortability before use
    Claude CodeNot declaredNo explicit evidencePortability before use
    CursorNot declaredNo explicit evidencePortability before use
    Gemini CLINot declaredNo explicit evidencePortability before use
    Open the compatibility checker

    Installation

    Inspect first. Install second.

    The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

    Source-detected install commandSource
    npx skills add https://github.com/brianwestphal/glassbox --skill ".claude/skills/kerf-app"
    Safe inspection promptEditorial

    Inspect the Agent Skill "kerf-app" from https://github.com/brianwestphal/glassbox/blob/0f2fd17891511441538204dcf832d51b0f4e2e6c/.claude/skills/kerf-app/SKILL.md at commit 0f2fd17891511441538204dcf832d51b0f4e2e6c. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.

    Workflow

    What the source asks the agent to do

    1. 01

      Setup

      Install: npm install kerfjs

      Install: npm install kerfjstsconfig.json: "jsx": "react-jsx", "jsxImportSource": "kerfjs"Vite / esbuild need no extra config.
    2. 02

      Workflow guidance

      When the user asks you to add a feature to a kerf app:

      Check what state already exists. Is there a signal / store you should reuse? Don't create a new one for derived data — use computed.Decide where state lives. Module-scope signal for ephemeral UI state; defineStore for state shared across mounts or that needs reset() for tests.Decide who fires the action. A handler on a DOM event → delegate with a data-action attribute. A signal change → effect().
    3. 03

      Public API — one import path

      Review the “Public API — one import path” section in the pinned source before continuing.

      Review and apply the “Public API — one import path” source section.
    4. 04

      Hard rules — every AI assistant gets these wrong at least once

      1. JSX renders to HTML strings, not DOM nodes. Don't pass DOM nodes as JSX children — the runtime throws. Need a ref? Build the JSX, then querySelector after mount() / toElement(). 2. Diff keys: id first, then data-key. Lists MUST set data-key={item.id} per item — otherwise the…

      JSX renders to HTML strings, not DOM nodes. Don't pass DOM nodes as JSX children — the runtime throws. Need a ref? Build the JSX, then querySelector after mount() / toElement().Diff keys: id first, then data-key. Lists MUST set data-key={item.id} per item — otherwise the diff matches by position and you lose focus, cursor, and identity on insert/delete.Three escape hatches for the morph:
    5. 05

      Decision-making axes

      When deciding which primitive to reach for, work down the axes:

      Originates inside the mount tree → delegate(rootEl, type, sel, handler). Originates outside (window-level keyboard, online/offline, beforeunload) → native window.addEventListener at module top-level.Gesture that needs to follow an element after press (drag, draw, resize) → at the start event, el.setPointerCapture(e.pointerId). Subsequent pointermove / pointerup redirect to the captured element and delegate(rootEl,…Well-known non-bubbler (focus, blur, scroll, load, error, mouseenter, mouseleave) → still delegate(); it auto-promotes to capture. Custom non-bubblers or capture-phase interception → delegateCapture() (also closest()-ma…

    Permission review

    Static risk signals and limitations

    No configured static risk pattern was detected

    This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.

    Evidence record

    Why each signal appears

    EvidenceSourceComputedTestedEditorial
    SignalValueEvidence typeMeaning
    Quality score92/100ComputedDocumentation, specificity, maintenance, and trust rules
    Repository stars34SourceRepository attention, not individual Skill quality
    Compatibility0 platformsSourceDeclared in the catalog source record
    Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

    Pinned source

    Provenance and original SKILL.md

    Repository
    brianwestphal/glassbox
    Skill path
    .claude/skills/kerf-app/SKILL.md
    Commit
    0f2fd17891511441538204dcf832d51b0f4e2e6c
    License
    MIT
    Collected
    2026-08-28
    Default branch
    main
    View the original SKILL.md

    Building apps with kerf

    Drop this file into your ~/.claude/skills/kerf-app/SKILL.md (or your project's .claude/skills/kerf-app/SKILL.md) so Claude Code activates it whenever you work on a kerf app.

    kerf is a ~12 KB reactive UI framework (~13 KB with arraySignal): signals + DOM morphing + JSX → HTML strings. No virtual DOM, no compiler, no scheduler. The whole public surface fits in 17 exports.

    Setup

    • Install: npm install kerfjs
    • tsconfig.json: "jsx": "react-jsx", "jsxImportSource": "kerfjs"
    • Vite / esbuild need no extra config.
    • Dev diagnostics are opt-in by import, and only an APP installs them. kerf does not infer dev mode. In the app entry add if (import.meta.env.DEV) await import('kerfjs/dev'); (Vite) or if (process.env.NODE_ENV !== 'production') await import('kerfjs/dev'); (webpack/Node). That enables the read-only store get() snapshot, the throwing dangerous-URL screen, and makes the KERF_DEV_WARN_* family available; omitting it is production shape and sheds ~4.7 KB min+gzip because the condition folds away and the chunk is never emitted. Put it FIRST if relying on the untracked-signal warning — signal() picks its constructor at creation time.
      • Switch individual warnings on with enableWarnings(), which is the only switch that works in a browser (no process object there, and a bundler define cannot reach the read): const dev = await import('kerfjs/dev'); dev.enableWarnings({ staleBinding: true, narrowSet: true, invariants: 'throw' });. The KERF_DEV_WARN_* env vars do the same for Node/SSR/CI; an explicit call wins either way.
      • A component package must NEVER import kerfjs/dev. The hooks are process-global, so installing them is the consuming app's decision — a library that does it forces the diagnostics (and the chunk) on every consumer. Put the import in your demo page or test harness instead.
    • Recommended companion: npm install --save-dev eslint-plugin-kerfjs and add kerfjs.configs.recommended to the project's eslint config. Enforces five of the hard rules below (no inline JSX event handlers, require data-key in each(), capture delegate() disposers, no nested mount(), prefer module JSX augmentation) at edit time — useful as a self-correction signal when authoring kerf code.

    Public API — one import path

    import {
      signal, computed, effect, batch,    // reactivity
      defineStore, resetAllStores,        // stores
      mount, morph, each,                 // render (reactive + one-shot) + keyed list
      delegate, delegateCapture,          // events
      toElement,                          // direct JSX → DOM Element (or DocumentFragment for multi-root)
      SafeHtml, isSafeHtml, raw, Fragment,
    } from 'kerfjs';
    
    // Optional, only when you need granular collection updates:
    import { arraySignal } from 'kerfjs/array-signal';
    
    // Development diagnostics — gate with YOUR build's dev flag, in YOUR code.
    if (import.meta.env.DEV) await import('kerfjs/dev');
    
    ExportUse
    signal(initial)atomic reactive state; .value get/set
    computed(fn)derived value, read-only
    effect(fn)side effect on signal change; returns disposer
    batch(fn)coalesce multiple writes into one re-run
    defineStore({initial, actions})named multi-consumer state
    resetAllStores()reset every store (test teardown)
    mount(el, render)bind reactive render to a DOM element; returns disposer
    morph(liveRoot, template)one-shot reconcile against a populated element (SSR hydration, page-refresh diffs). Template = Element, SafeHtml, or HTML string
    each(items, render, cacheKey?)keyed list iteration; per-row memoization on identity (+ optional cacheKey — a passive comparator for external state). Distinct from data-key on the rendered element
    each(items, render, { cacheKey, key })same, options form. key gives the list a stable identity — required whenever a conditional list can render before this one, else kerf rebuilds this list and its rows lose focus/scroll/IME. A keyed list takes no positional slot, so keying the conditional list usually fixes its siblings too
    delegate(root, type, sel, h)one listener at the root; closest(selector) walk from target
    delegateCapture(root, type, sel, h, opts?)capture-phase escape hatch; closest() walk-up by default (same as delegate); pass { match: 'direct' } for strict target.matches()
    attr(name, value)pre-computed AttrSpec<N,V>.selector for delegate(), .attrs to spread into JSX (rename-safe)
    attr(name)dynamic factory — attr<N,V=string>(name) returns (value: V) => { readonly [name]: V }; both generics off → N inferred, V defaults to string; specify both to constrain values
    toElement(jsx)parse JSX into a DOM node (SVG-aware). Single-root → Element; multi-root (<><svg/> label</>, two icons side by side) → DocumentFragment that appendChild/replaceChildren/append inlines into the parent.
    raw(html)inject pre-escaped HTML
    arraySignal(initial?)granular keyed-list signal (subpath kerfjs/array-signal); each() reconciles in O(patches)
    html`…`tagged template (subpath kerfjs/html) — JSX-identical runtime semantics with NO build step, for CDN/importmap projects. Real HTML attribute names (class, not className); holes only in text positions or as a COMPLETE attribute value (attr=${v} / attr="${v}")

    Hard rules — every AI assistant gets these wrong at least once

    1. JSX renders to HTML strings, not DOM nodes. Don't pass DOM nodes as JSX children — the runtime throws. Need a ref? Build the JSX, then querySelector after mount() / toElement().
    2. Diff keys: id first, then data-key. Lists MUST set data-key={item.id} per item — otherwise the diff matches by position and you lose focus, cursor, and identity on insert/delete.
    3. Three escape hatches for the morph:
      • data-morph-skip — element AND subtree preserved verbatim. For library-owned hosts (Monaco, xterm, D3).
      • data-morph-skip-children — attrs on the host morph, subtree preserved. For client-hydrated slots whose loading/state classes need to flow through.
      • data-morph-preserve — element survives the trailing-removal pass even when the new template doesn't emit it. For imperatively-injected children (autoplay video, tooltip overlay, analytics pixel). Does NOT block a keyed-match move.
    4. Never addEventListener inside a mount()-managed tree unless under data-morph-skip. A morph re-render may discard the node. Use delegate / delegateCapture instead.
    5. Capture the delegate() / delegateCapture() disposer whenever the registration's scope is shorter than the page. Both helpers return () => void; the listener closure pins rootEl, handler, and everything the handler closes over (stores, signals, app state). Discarding the disposer on a transient root (modal, route view, mount swap, dynamic widget) leaks the listener AND the app graph it captures; re-mount cycles stack listeners linearly. mount()'s own disposer does NOT remove delegates for you. Safe to discard only when the registration is truly page-lifetime (root is document.body or equivalent, attached once at startup, never torn down).
    6. One mount() per root. Don't nest mount() calls. Compose with plain functions returning JSX.
    7. Components are plain functions. <MyComponent props /> works — the JSX runtime calls MyComponent(props) and uses the returned JSX — but there's no hook system, no lifecycle, and no per-instance state. State lives in module-scope signals or stores, never in component closures.
    8. Values bind, structure re-renders. For a value hole, pass the signal/computed ITSELF (<span>{count}</span>, class={sig}) — kerf updates that one node directly, no render re-run. Read .value only when the JSX structure depends on the signal — and then the read must happen INSIDE the render function to be tracked: const x = count.value; mount(el, () => <span>{x}</span>) does NOT re-render. One caveat on bound holes: bind a STABLE signal/computed instance per hole (class={computed(() => …)} that switches internally), never class={cond ? sigA : sigB} — switching instances can go silently stale (detectable via KERF_DEV_WARN_STALE_BINDING=1). The idiom's endpoint: a render that reads NO .value runs exactly once — a fully bound mount never re-renders. To find .value holes worth migrating, KERF_DEV_WARN_VALUE_ONLY_RERENDER=1 flags re-renders whose only differences were text/attribute values.
    9. Store actions take (set, get), not (state). set(next) replaces state; mutating get() does nothing.
    10. Use data-action attributes, not inline onClick. Inline handlers are NOT supported by the JSX → string runtime; delegate from the root.
    11. arraySignal is opt-in for long keyed lists where most updates are pointwise. For short lists / filter+sort pipelines, plain signal + each(items.value, ...) is simpler and equally fast.
    12. Custom-element types: declaration-merge into kerfjs/jsx-runtime, NOT into a global JSX namespace. Pattern: declare module 'kerfjs/jsx-runtime' { namespace JSX { interface IntrinsicElements { 'my-tag': KerfCustomElement & { foo?: string } } } }.
    13. Each each() row must produce exactly one top-level element. Multi-root or empty rows throw a row-precise error. Wrap multiple roots in one parent.
    14. each() is for DYNAMIC lists. Use .map() for static structural arrays (constant COLUMNS / TABS / settings sections) whose row render reads signals. each() memoizes per-item HTML by object identity; constant items never change identity, so the cache hits forever, the row render is never re-invoked, and signal reads inside it silently stop tracking. Outer .map() for the static frame + inner each() for the dynamic sub-list is the idiomatic shape.

    Decision-making axes

    When deciding which primitive to reach for, work down the axes:

    Events.

    • Originates inside the mount tree → delegate(rootEl, type, sel, handler). Originates outside (window-level keyboard, online/offline, beforeunload) → native window.addEventListener at module top-level.
    • Gesture that needs to follow an element after press (drag, draw, resize) → at the start event, el.setPointerCapture(e.pointerId). Subsequent pointermove / pointerup redirect to the captured element and delegate(rootEl, 'pointermove', '[data-card]', …) still picks them up. Don't reach for window.addEventListener for in-mount-tree gestures.
    • Well-known non-bubbler (focus, blur, scroll, load, error, mouseenter, mouseleave) → still delegate(); it auto-promotes to capture. Custom non-bubblers or capture-phase interception → delegateCapture() (also closest()-matched by default). Need strict element-match? Add { match: 'direct' } on either helper.

    Lists.

    • Items change across renders (todos, chat messages, table rows) → each(items, render).
    • Static structural enumeration whose row render reads signals → STATIC.map(item => <jsx/>). Inner each(item.children, …) still gets keyed reconcile.
    • Long list with point-wise mutations → arraySignal + each(arraySig, render) for O(patches) updates.

    Side effects / imperative DOM.

    • Library-owned subtree survives across renders → data-morph-skip on host.
    • Host attributes morph but subtree preserved → data-morph-skip-children.
    • Imperatively-injected element survives the trailing-removal pass → data-morph-preserve.
    • Focused input / contenteditable caret survives re-renders → automatic; no opt-in.

    Raw HTML.

    • User-controlled HTML → sanitize first (DOMPurify) then raw(sanitized).
    • Author-controlled trusted HTML → raw(html) directly.

    Dangerous URLs. javascript:/vbscript:/script-executing data: values on href/src/xlink:href/formaction/action/data are dropped — kerf throws in dev, warns + drops in prod. Sanitize user URLs upstream; wrap an intentional trusted one in raw(url) (bypasses the screen in both modes). The javascript: no-op placeholders (javascript:void(0), javascript:;, …) are allowed — they're the placeholder-link idiom, matched against the whole value so nothing can ride along.

    Canonical patterns

    // Pattern 1: signal + mount + delegate.
    // THE core idiom — values bind, structure re-renders: pass the signal ITSELF
    // into a value hole ({count}, class={sig}) so kerf updates that one node
    // directly with no render re-run; read `.value` only when the JSX STRUCTURE
    // depends on the signal (conditionals, list shape).
    const count = signal(0);
    const ACTIONS = { inc: attr('data-action', 'inc') } as const satisfies Record<string, AttrSpec<'data-action'>>;
    
    mount(document.getElementById('app')!, () => (
      <div>
        <button {...ACTIONS.inc.attrs}>+</button>
        <span>{count}</span>
      </div>
    ));
    delegate(rootEl, 'click', ACTIONS.inc.selector, () => { count.value += 1; });
    
    // Pattern 2: keyed list with per-row memoization
    mount(listEl, () => (
      <ul>
        {each(rows.value, (row) => <li data-key={row.id}>{row.label}</li>)}
      </ul>
    ));
    
    // Pattern 3: store with reset
    const cart = defineStore({
      initial: () => ({ items: [] as string[] }),
      actions: (set, get) => ({
        add:   (id: string) => set({ items: [...get().items, id] }),
        clear: ()           => set({ items: [] }),
      }),
    });
    // access: cart.state.value.items, cart.actions.add('x'), cart.reset()
    
    // Pattern 4: one-shot reconcile (no signals, no effect)
    morph(liveCard, '<article class="card">…</article>');
    
    // Pattern 5: fine-grained binding (opt-in) — pass the signal/computed ITSELF
    // into a hole so a change updates ONLY that node (no render re-run, no
    // reconcile). For a hot spot driven by an external signal (selection class,
    // live status attr) — not everywhere. Use computed(), never a bare () => ….
    const selectedId = signal<number | null>(null);
    mount(listEl, () => (
      <ul>
        {each(rows.value, (row) => (
          <li class={computed(() => (row.id === selectedId.value ? 'sel' : ''))}>{row.label}</li>
        ), (row) => row.id)}
      </ul>
    ));
    // selectedId.value = 3  → only the ~2 affected <li> class attrs update.
    
    // Pattern 6: no build step (CDN / importmap) — the html tagged template
    // instead of JSX. Same runtime semantics; real HTML attribute names; a hole
    // must be a text position or a COMPLETE attribute value (partials throw).
    import { html } from 'kerfjs/html';
    mount(rootEl, () => html`
      <div class="${cls}">Count: ${count}</div>
      <ul>${each(rows.value, (row) => html`<li data-key="${row.id}">${row.label}</li>`)}</ul>
    `);
    

    Diagnosing common errors

    Error / symptomRoot causeFix
    JSX: DOM elements cannot be passed as childrenpassed a toElement() result inside JSXBuild the whole tree in JSX; refs via querySelector after rendering
    draggable={true} / spellCheck={false} / contentEditable={false} / writingsuggestions={false} / translate={false} / autocorrect={false} won't typecheckthese are HTML enumerated attributes, not boolean ones — they take keyword strings ("true"/"false"; "yes"/"no" for translate; "on"/"off" for autocorrect), and omitting one selects a third state, so the boolean form rendered the opposite of what was meantWrite the keyword: draggable="true", spellCheck="false", writingsuggestions="false", translate="no", autocorrect="off". Omit for the default state. Real boolean attrs (hidden, checked, disabled, autofocus, required, inert) are unaffected, as is popover (bare form = the spec's auto state); for a signal use signal('true')
    <select value={x}> / <textarea value={x}> won't typecheckneither element has a value content attribute — the markup was inert<option value="b" selected>; <textarea>{draft}</textarea>
    Focus / cursor lost on every keystrokelist items lack data-keyAdd data-key (or id) to each list item
    Click handler stops firing after re-renderel.addEventListener was usedReplace with delegate(rootEl, 'click', ACTIONS.foo.selector, ...) (or a string literal for ad-hoc cases)
    Render fn never re-runssignal was read outside the render fnMove signal.value read inside the render fn
    SVG renders as broken / namespaceless markupinnerHTML used directlyUse mount or toElement (SVG-aware)
    Library widget destroyed on every renderhost reachable by the morphWrap host in data-morph-skip; mount the library imperatively after first render
    <my-tag> fails to typecheckdeclaration merging targeted global JSXUse declare module 'kerfjs/jsx-runtime' { namespace JSX { … } } instead
    each(): row render at index N produced K top-level elementsrow returned multiple sibling elements or zeroWrap them in one parent so the row renders exactly one element
    Drag/drop / state change has no visible effect; only elements outside each() updateUsed each(STATIC_ARRAY, …) whose row render reads signals. Items never change identity → cache hits forever → row render never re-invoked → signal reads stop trackingReplace outer with STATIC_ARRAY.map(...); keep inner each() for the dynamic sub-list. See Hard Rule 14
    Row-enter CSS animation no longer replays when only a row's content changed (kerf ≥ 0.15.0)0.15.0+ morphs a same-identity, same-position row in place instead of recreating its node, so a mount-keyed @keyframes never re-triggers on a content-only update (≤ 0.14.x recreated the node, so it fired). Intentional flip side: focus, scroll, IME, and in-progress transitions now surviveKey the animation on a state-class toggle, not element creation. To force a remount, churn the row's identity (new object ref / data-key) so the reconciler replaces the node
    Want a hot spot to update without re-running the whole renderFine-grained binding: pass the signal/computed ITSELF into the attr/text hole (class={computed(() => …)}), not .value. Use computed() not a bare () => … (memoization keeps a shared-signal flip to ~O(changed nodes)). Opt-in per hole. Limit: a bound hole depending on the row's OWN mutated data goes stale on a granular in-place update — use plain interpolation there
    html ``: partial attribute values are not supportedIn kerfjs/html templates a hole must be the COMPLETE attribute valueBuild the full string first (class="${`a ${b}`}"), or bind class="${computed(() => a ${b.value})}" for a reactive one
    An each() list's rows lose focus / scroll / typing state when an unrelated conditional list above them appears or disappears (kerf warns about this in dev)Lists without a key are identified by their position among the render's each() calls, so adding/removing one above shifts this list's identity and kerf rebuilds itGive the lists stable keys: each(items, render, { key: 'results' }). Keying just the conditional list is usually enough
    Keyed each() list suddenly renders zero rows — only its <!--kf-list:N--> marker — with no errors, and it never recovers (kerfjs ≤ 2.0.1)A conditionally-rendered sibling BEFORE the list (possibly higher in the tree, e.g. an error banner) was removed that render; older kerfjs rebuilt the shifted list container from the template, permanently detaching the list's internal bindingUpgrade kerfjs (fixed after 2.0.1 — the morph now moves the shifted container up in place, keeping node identity). On older versions, keep the structure before the list stable: wrap the conditional in an always-present container (<div class="banners">{cond ? <div/> : ''}</div>)
    A numbered / zebra-striped / "N of M" each() list shows the wrong number on rows that MOVED (reorder, or non-tail insert/remove), while unmoved rows look rightThe render fn's index argument is NOT part of the memo key (only item identity + cacheKey + content version are), so a row that keeps identity but changes position keeps the HTML it rendered at its old indexFold the index into the memo key so displaced rows re-render: each(items, (it, i) => …, { cacheKey: (_, i) => i }) (add key if used). Opt-in dev warn: KERF_DEV_WARN_STALE_INDEX=1

    Workflow guidance

    When the user asks you to add a feature to a kerf app:

    1. Check what state already exists. Is there a signal / store you should reuse? Don't create a new one for derived data — use computed.
    2. Decide where state lives. Module-scope signal for ephemeral UI state; defineStore for state shared across mounts or that needs reset() for tests.
    3. Decide who fires the action. A handler on a DOM event → delegate with a data-action attribute. A signal change → effect().
    4. Render output is JSX returning SafeHtml. No JSX-as-DOM-node, no inline handlers. Lists get data-key.
    5. Test with kerfjs/testing's clearStoreRegistry() between unit tests if you used defineStore.

    When you spot user code that violates any of the hard rules above, fix it inline AND explain the rule briefly so the user learns the pattern.

    Server / SSR

    SafeHtml.toString() returns the HTML string. JSX works in Node with no DOM. mount, morph, delegate, toElement all require a DOM and run client-side.

    Where to look next

    Frequently asked questions

    What to verify before installation and use

    What does the kerf-app source document cover?

    Drop this file into your /.claude/skills/kerf-app/SKILL.md (or your project's .claude/skills/kerf-app/SKILL.md) so Claude Code activates it whenever you work on a kerf app.

    How do I install kerf-app?

    The source record exposes this install command: npx skills add https://github.com/brianwestphal/glassbox --skill ".claude/skills/kerf-app". Inspect the command and pinned source before running it.

    Alternatives

    Compare before choosing

    Computed 10045,960

    coreyhaines31/marketingskills

    ab-testing

    When the user wants to plan, design, or implement an A/B test or experiment, or build a growth experimentation program. Also use when the user mentions "A/B test," "split test," "experiment," "test this change," "variant copy," "multivariate test," "hypothesis," "should I test this," "which version is better," "test two versions," "statistical significance," "how long should I run this test," "growth experiments," "experiment velocity," "experiment backlog," "ICE score," "experimentation program

    Computed 10029,236

    garrytan/gbrain

    bulk-ingestion

    End-to-end discipline for turning any large data source (audio libraries, email takeouts, document corpora, chat exports, API dumps) into brain pages at scale. The lifecycle spine: SCHEMA → ACCESS → TRIAL → EVALUATE → IMPROVE → CODIFY → TEST → SKILLIFY → BULK → MONITOR. State is tracked in a durable JSON manifest (see MANIFEST-PATTERN.md) so any crash, session boundary, or subagent fan-out resumes from ground truth instead of memory.

    Computed 10025,136

    alirezarezvani/claude-skills

    app-store-optimization

    App Store Optimization (ASO) toolkit for researching keywords, analyzing competitor rankings, generating metadata suggestions, and improving app visibility on Apple App Store and Google Play Store. Use when the user asks about ASO, app store rankings, app metadata, app titles and descriptions, app store listings, app visibility, or mobile app marketing on iOS or Android. Supports keyword research and scoring, competitor keyword analysis, metadata optimization, A/B test planning, launch checklist

    Computed 1005,277

    dotnet/skills

    migrate-vstest-to-mtp

    Migrates .NET test projects from VSTest to Microsoft.Testing.Platform (MTP). Use when user asks to "migrate to MTP", "switch from VSTest", "enable Microsoft.Testing.Platform", "use MTP runner", set OutputType=Exe only for test projects in Directory.Build.props, or mentions EnableMSTestRunner, EnableNUnitRunner, or UseMicrosoftTestingPlatformRunner. USE FOR: MTP behavioral differences vs VSTest (exit code 8, zero tests discovered, --ignore-exit-code, TESTINGPLATFORM_EXITCODE_IGNORE); centralizing