{"owner":"gsd-build","repo":"gsd-2","hasSkills":true,"totalSkillsCount":358,"totalTokensCount":236704,"categories":["subagent-persona","anthropic-skill","plugin-manifest"],"hasMcp":false,"mcpConfig":null,"found":["docs/agents/domain.md","docs/agents/issue-tracker.md","docs/agents/triage-labels.md","gsd-orchestrator/SKILL.md","packages/mcp-server/README.md","packages/rpc-client/README.md","src/resources/extensions/gsd/docs/COORDINATION.md","src/resources/extensions/gsd/docs/claude-marketplace-import.md","src/resources/extensions/gsd/docs/preferences-reference.md","src/resources/extensions/gsd/prompts/heal-skill.md","src/resources/extensions/gsd/prompts/system.md","src/resources/extensions/gsd/skills/gsd-headless/SKILL.md","src/resources/extensions/gsd/skills/gsd-headless/references/answer-injection.md","src/resources/extensions/gsd/skills/gsd-headless/references/commands.md","src/resources/extensions/gsd/skills/gsd-headless/references/multi-session.md","src/resources/extensions/gsd/templates/milestone-summary.md","src/resources/extensions/gsd/templates/slice-summary.md","src/resources/extensions/gsd/templates/task-summary.md","src/resources/skills/accessibility/SKILL.md","src/resources/skills/accessibility/references/WCAG.md","src/resources/skills/agent-browser/SKILL.md","src/resources/skills/agent-browser/references/authentication.md","src/resources/skills/agent-browser/references/commands.md","src/resources/skills/agent-browser/references/profiling.md","src/resources/skills/agent-browser/references/proxy-support.md","src/resources/skills/agent-browser/references/session-management.md","src/resources/skills/agent-browser/references/snapshot-refs.md","src/resources/skills/agent-browser/references/video-recording.md","src/resources/skills/api-design/SKILL.md","src/resources/skills/best-practices/SKILL.md","src/resources/skills/btw/SKILL.md","src/resources/skills/code-optimizer/SKILL.md","src/resources/skills/code-optimizer/references/algorithmic-complexity.md","src/resources/skills/code-optimizer/references/build-compilation.md","src/resources/skills/code-optimizer/references/bundle-dependencies.md","src/resources/skills/code-optimizer/references/caching-memoization.md","src/resources/skills/code-optimizer/references/concurrency-async.md","src/resources/skills/code-optimizer/references/config-infra.md","src/resources/skills/code-optimizer/references/data-structures.md","src/resources/skills/code-optimizer/references/database-queries.md","src/resources/skills/code-optimizer/references/dead-code-redundancy.md","src/resources/skills/code-optimizer/references/error-resilience.md","src/resources/skills/code-optimizer/references/io-network.md","src/resources/skills/code-optimizer/references/logging-observability.md","src/resources/skills/code-optimizer/references/memory-resources.md","src/resources/skills/code-optimizer/references/rendering-ui.md","src/resources/skills/code-optimizer/references/security-performance.md","src/resources/skills/core-web-vitals/SKILL.md","src/resources/skills/core-web-vitals/references/LCP.md","src/resources/skills/create-gsd-extension/SKILL.md","src/resources/skills/create-gsd-extension/references/compaction-session-control.md","src/resources/skills/create-gsd-extension/references/custom-commands.md","src/resources/skills/create-gsd-extension/references/custom-rendering.md","src/resources/skills/create-gsd-extension/references/custom-tools.md","src/resources/skills/create-gsd-extension/references/custom-ui.md","src/resources/skills/create-gsd-extension/references/events-reference.md","src/resources/skills/create-gsd-extension/references/extension-lifecycle.md","src/resources/skills/create-gsd-extension/references/extensionapi-reference.md","src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md","src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md","src/resources/skills/create-gsd-extension/references/mode-behavior.md","src/resources/skills/create-gsd-extension/references/model-provider-management.md","src/resources/skills/create-gsd-extension/references/packaging-distribution.md","src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md","src/resources/skills/create-gsd-extension/references/state-management.md","src/resources/skills/create-gsd-extension/references/system-prompt-modification.md","src/resources/skills/create-gsd-extension/workflows/add-capability.md","src/resources/skills/create-gsd-extension/workflows/create-extension.md","src/resources/skills/create-gsd-extension/workflows/debug-extension.md","src/resources/skills/create-mcp-server/SKILL.md","src/resources/skills/create-skill/SKILL.md","src/resources/skills/create-skill/references/api-security.md","src/resources/skills/create-skill/references/be-clear-and-direct.md","src/resources/skills/create-skill/references/common-patterns.md","src/resources/skills/create-skill/references/core-principles.md","src/resources/skills/create-skill/references/executable-code.md","src/resources/skills/create-skill/references/gsd-skill-ecosystem.md","src/resources/skills/create-skill/references/iteration-and-testing.md","src/resources/skills/create-skill/references/recommended-structure.md","src/resources/skills/create-skill/references/skill-structure.md","src/resources/skills/create-skill/references/use-xml-tags.md","src/resources/skills/create-skill/references/using-scripts.md","src/resources/skills/create-skill/references/using-templates.md","src/resources/skills/create-skill/references/workflows-and-validation.md","src/resources/skills/create-skill/templates/router-skill.md","src/resources/skills/create-skill/templates/simple-skill.md","src/resources/skills/create-skill/workflows/add-reference.md","src/resources/skills/create-skill/workflows/add-script.md","src/resources/skills/create-skill/workflows/add-template.md","src/resources/skills/create-skill/workflows/add-workflow.md","src/resources/skills/create-skill/workflows/audit-skill.md","src/resources/skills/create-skill/workflows/create-new-skill.md","src/resources/skills/create-skill/workflows/get-guidance.md","src/resources/skills/create-skill/workflows/upgrade-to-router.md","src/resources/skills/create-skill/workflows/verify-skill.md","src/resources/skills/create-workflow/SKILL.md","src/resources/skills/create-workflow/references/feature-patterns.md","src/resources/skills/create-workflow/references/verification-policies.md","src/resources/skills/create-workflow/references/yaml-schema-v1.md","src/resources/skills/create-workflow/templates/blog-post-pipeline.yaml","src/resources/skills/create-workflow/templates/code-audit.yaml","src/resources/skills/create-workflow/templates/release-checklist.yaml","src/resources/skills/create-workflow/templates/workflow-definition.yaml","src/resources/skills/create-workflow/workflows/create-from-scratch.md","src/resources/skills/create-workflow/workflows/create-from-template.md","src/resources/skills/debug-like-expert/SKILL.md","src/resources/skills/debug-like-expert/references/debugging-mindset.md","src/resources/skills/debug-like-expert/references/hypothesis-testing.md","src/resources/skills/debug-like-expert/references/investigation-techniques.md","src/resources/skills/debug-like-expert/references/verification-patterns.md","src/resources/skills/debug-like-expert/references/when-to-research.md","src/resources/skills/decompose-into-slices/SKILL.md","src/resources/skills/dependency-upgrade/SKILL.md","src/resources/skills/design-an-interface/SKILL.md","src/resources/skills/forensics/SKILL.md","src/resources/skills/frontend-design/SKILL.md","src/resources/skills/github-workflows/SKILL.md","src/resources/skills/github-workflows/references/gh/SKILL.md","src/resources/skills/github-workflows/references/gh/references/issue-stories.md","src/resources/skills/github-workflows/references/gh/references/labels.md","src/resources/skills/github-workflows/references/gh/references/milestones.md","src/resources/skills/github-workflows/references/gh/references/projects-v2.md","src/resources/skills/grill-me/SKILL.md","src/resources/skills/handoff/SKILL.md","src/resources/skills/lint/SKILL.md","src/resources/skills/make-interfaces-feel-better/SKILL.md","src/resources/skills/make-interfaces-feel-better/animations.md","src/resources/skills/make-interfaces-feel-better/performance.md","src/resources/skills/make-interfaces-feel-better/surfaces.md","src/resources/skills/make-interfaces-feel-better/typography.md","src/resources/skills/observability/SKILL.md","src/resources/skills/react-best-practices/README.md","src/resources/skills/react-best-practices/SKILL.md","src/resources/skills/react-best-practices/metadata.json","src/resources/skills/react-best-practices/rules/_sections.md","src/resources/skills/react-best-practices/rules/_template.md","src/resources/skills/react-best-practices/rules/advanced-event-handler-refs.md","src/resources/skills/react-best-practices/rules/advanced-init-once.md","src/resources/skills/react-best-practices/rules/advanced-use-latest.md","src/resources/skills/react-best-practices/rules/async-api-routes.md","src/resources/skills/react-best-practices/rules/async-defer-await.md","src/resources/skills/react-best-practices/rules/async-dependencies.md","src/resources/skills/react-best-practices/rules/async-parallel.md","src/resources/skills/react-best-practices/rules/async-suspense-boundaries.md","src/resources/skills/react-best-practices/rules/bundle-barrel-imports.md","src/resources/skills/react-best-practices/rules/bundle-conditional.md","src/resources/skills/react-best-practices/rules/bundle-defer-third-party.md","src/resources/skills/react-best-practices/rules/bundle-dynamic-imports.md","src/resources/skills/react-best-practices/rules/bundle-preload.md","src/resources/skills/react-best-practices/rules/client-event-listeners.md","src/resources/skills/react-best-practices/rules/client-localstorage-schema.md","src/resources/skills/react-best-practices/rules/client-passive-event-listeners.md","src/resources/skills/react-best-practices/rules/client-swr-dedup.md","src/resources/skills/react-best-practices/rules/js-batch-dom-css.md","src/resources/skills/react-best-practices/rules/js-cache-function-results.md","src/resources/skills/react-best-practices/rules/js-cache-property-access.md","src/resources/skills/react-best-practices/rules/js-cache-storage.md","src/resources/skills/react-best-practices/rules/js-combine-iterations.md","src/resources/skills/react-best-practices/rules/js-early-exit.md","src/resources/skills/react-best-practices/rules/js-hoist-regexp.md","src/resources/skills/react-best-practices/rules/js-index-maps.md","src/resources/skills/react-best-practices/rules/js-length-check-first.md","src/resources/skills/react-best-practices/rules/js-min-max-loop.md","src/resources/skills/react-best-practices/rules/js-set-map-lookups.md","src/resources/skills/react-best-practices/rules/js-tosorted-immutable.md","src/resources/skills/react-best-practices/rules/rendering-activity.md","src/resources/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md","src/resources/skills/react-best-practices/rules/rendering-conditional-render.md","src/resources/skills/react-best-practices/rules/rendering-content-visibility.md","src/resources/skills/react-best-practices/rules/rendering-hoist-jsx.md","src/resources/skills/react-best-practices/rules/rendering-hydration-no-flicker.md","src/resources/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md","src/resources/skills/react-best-practices/rules/rendering-svg-precision.md","src/resources/skills/react-best-practices/rules/rendering-usetransition-loading.md","src/resources/skills/react-best-practices/rules/rerender-defer-reads.md","src/resources/skills/react-best-practices/rules/rerender-dependencies.md","src/resources/skills/react-best-practices/rules/rerender-derived-state-no-effect.md","src/resources/skills/react-best-practices/rules/rerender-derived-state.md","src/resources/skills/react-best-practices/rules/rerender-functional-setstate.md","src/resources/skills/react-best-practices/rules/rerender-lazy-state-init.md","src/resources/skills/react-best-practices/rules/rerender-memo-with-default-value.md","src/resources/skills/react-best-practices/rules/rerender-memo.md","src/resources/skills/react-best-practices/rules/rerender-move-effect-to-event.md","src/resources/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md","src/resources/skills/react-best-practices/rules/rerender-transitions.md","src/resources/skills/react-best-practices/rules/rerender-use-ref-transient-values.md","src/resources/skills/react-best-practices/rules/server-after-nonblocking.md","src/resources/skills/react-best-practices/rules/server-auth-actions.md","src/resources/skills/react-best-practices/rules/server-cache-lru.md","src/resources/skills/react-best-practices/rules/server-cache-react.md","src/resources/skills/react-best-practices/rules/server-dedup-props.md","src/resources/skills/react-best-practices/rules/server-parallel-fetching.md","src/resources/skills/react-best-practices/rules/server-serialization.md","src/resources/skills/review/SKILL.md","src/resources/skills/security-review/SKILL.md","src/resources/skills/spike-wrap-up/SKILL.md","src/resources/skills/tdd/SKILL.md","src/resources/skills/test/SKILL.md","src/resources/skills/userinterface-wiki/SKILL.md","src/resources/skills/userinterface-wiki/rules/_sections.md","src/resources/skills/userinterface-wiki/rules/_template.md","src/resources/skills/userinterface-wiki/rules/a11y-reduced-motion-check.md","src/resources/skills/userinterface-wiki/rules/a11y-toggle-setting.md","src/resources/skills/userinterface-wiki/rules/a11y-visual-equivalent.md","src/resources/skills/userinterface-wiki/rules/a11y-volume-control.md","src/resources/skills/userinterface-wiki/rules/appropriate-confirmations-only.md","src/resources/skills/userinterface-wiki/rules/appropriate-errors-warnings.md","src/resources/skills/userinterface-wiki/rules/appropriate-no-decorative.md","src/resources/skills/userinterface-wiki/rules/appropriate-no-high-frequency.md","src/resources/skills/userinterface-wiki/rules/appropriate-no-punishing.md","src/resources/skills/userinterface-wiki/rules/container-callback-ref.md","src/resources/skills/userinterface-wiki/rules/container-guard-initial-zero.md","src/resources/skills/userinterface-wiki/rules/container-no-excessive-use.md","src/resources/skills/userinterface-wiki/rules/container-overflow-hidden.md","src/resources/skills/userinterface-wiki/rules/container-transition-delay.md","src/resources/skills/userinterface-wiki/rules/container-two-div-pattern.md","src/resources/skills/userinterface-wiki/rules/container-use-resize-observer.md","src/resources/skills/userinterface-wiki/rules/context-cleanup-nodes.md","src/resources/skills/userinterface-wiki/rules/context-resume-suspended.md","src/resources/skills/userinterface-wiki/rules/context-reuse-single.md","src/resources/skills/userinterface-wiki/rules/design-filter-for-character.md","src/resources/skills/userinterface-wiki/rules/design-noise-for-percussion.md","src/resources/skills/userinterface-wiki/rules/design-oscillator-for-tonal.md","src/resources/skills/userinterface-wiki/rules/duration-max-300ms.md","src/resources/skills/userinterface-wiki/rules/duration-press-hover.md","src/resources/skills/userinterface-wiki/rules/duration-shorten-before-curve.md","src/resources/skills/userinterface-wiki/rules/duration-small-state.md","src/resources/skills/userinterface-wiki/rules/easing-entrance-ease-out.md","src/resources/skills/userinterface-wiki/rules/easing-exit-ease-in.md","src/resources/skills/userinterface-wiki/rules/easing-for-state-change.md","src/resources/skills/userinterface-wiki/rules/easing-linear-only-progress.md","src/resources/skills/userinterface-wiki/rules/easing-natural-decay.md","src/resources/skills/userinterface-wiki/rules/easing-no-linear-motion.md","src/resources/skills/userinterface-wiki/rules/easing-transition-ease-in-out.md","src/resources/skills/userinterface-wiki/rules/envelope-exponential-decay.md","src/resources/skills/userinterface-wiki/rules/envelope-no-zero-target.md","src/resources/skills/userinterface-wiki/rules/envelope-set-initial-value.md","src/resources/skills/userinterface-wiki/rules/exit-key-required.md","src/resources/skills/userinterface-wiki/rules/exit-matches-initial.md","src/resources/skills/userinterface-wiki/rules/exit-prop-required.md","src/resources/skills/userinterface-wiki/rules/exit-requires-wrapper.md","src/resources/skills/userinterface-wiki/rules/impl-default-subtle.md","src/resources/skills/userinterface-wiki/rules/impl-preload-audio.md","src/resources/skills/userinterface-wiki/rules/impl-reset-current-time.md","src/resources/skills/userinterface-wiki/rules/mode-pop-layout-for-lists.md","src/resources/skills/userinterface-wiki/rules/mode-sync-layout-conflict.md","src/resources/skills/userinterface-wiki/rules/mode-wait-doubles-duration.md","src/resources/skills/userinterface-wiki/rules/morphing-aria-hidden.md","src/resources/skills/userinterface-wiki/rules/morphing-consistent-viewbox.md","src/resources/skills/userinterface-wiki/rules/morphing-group-variants.md","src/resources/skills/userinterface-wiki/rules/morphing-jump-non-grouped.md","src/resources/skills/userinterface-wiki/rules/morphing-reduced-motion.md","src/resources/skills/userinterface-wiki/rules/morphing-spring-rotation.md","src/resources/skills/userinterface-wiki/rules/morphing-strokelinecap-round.md","src/resources/skills/userinterface-wiki/rules/morphing-three-lines.md","src/resources/skills/userinterface-wiki/rules/morphing-use-collapsed.md","src/resources/skills/userinterface-wiki/rules/native-backdrop-styling.md","src/resources/skills/userinterface-wiki/rules/native-placeholder-styling.md","src/resources/skills/userinterface-wiki/rules/native-selection-styling.md","src/resources/skills/userinterface-wiki/rules/nested-consistent-timing.md","src/resources/skills/userinterface-wiki/rules/nested-propagate-required.md","src/resources/skills/userinterface-wiki/rules/none-context-menu-entrance.md","src/resources/skills/userinterface-wiki/rules/none-high-frequency.md","src/resources/skills/userinterface-wiki/rules/none-keyboard-navigation.md","src/resources/skills/userinterface-wiki/rules/param-click-duration.md","src/resources/skills/userinterface-wiki/rules/param-filter-frequency-range.md","src/resources/skills/userinterface-wiki/rules/param-q-value-range.md","src/resources/skills/userinterface-wiki/rules/param-reasonable-gain.md","src/resources/skills/userinterface-wiki/rules/physics-active-state.md","src/resources/skills/userinterface-wiki/rules/physics-no-excessive-stagger.md","src/resources/skills/userinterface-wiki/rules/physics-spring-for-overshoot.md","src/resources/skills/userinterface-wiki/rules/physics-subtle-deformation.md","src/resources/skills/userinterface-wiki/rules/prefetch-hit-slop.md","src/resources/skills/userinterface-wiki/rules/prefetch-keyboard-tab.md","src/resources/skills/userinterface-wiki/rules/prefetch-not-everything.md","src/resources/skills/userinterface-wiki/rules/prefetch-touch-fallback.md","src/resources/skills/userinterface-wiki/rules/prefetch-trajectory-over-hover.md","src/resources/skills/userinterface-wiki/rules/prefetch-use-selectively.md","src/resources/skills/userinterface-wiki/rules/presence-disable-interactions.md","src/resources/skills/userinterface-wiki/rules/presence-hook-in-child.md","src/resources/skills/userinterface-wiki/rules/presence-safe-to-remove.md","src/resources/skills/userinterface-wiki/rules/pseudo-content-required.md","src/resources/skills/userinterface-wiki/rules/pseudo-first-line-styling.md","src/resources/skills/userinterface-wiki/rules/pseudo-hit-target-expansion.md","src/resources/skills/userinterface-wiki/rules/pseudo-marker-styling.md","src/resources/skills/userinterface-wiki/rules/pseudo-over-dom-node.md","src/resources/skills/userinterface-wiki/rules/pseudo-position-relative-parent.md","src/resources/skills/userinterface-wiki/rules/pseudo-z-index-layering.md","src/resources/skills/userinterface-wiki/rules/spring-for-gestures.md","src/resources/skills/userinterface-wiki/rules/spring-for-interruptible.md","src/resources/skills/userinterface-wiki/rules/spring-params-balanced.md","src/resources/skills/userinterface-wiki/rules/spring-preserves-velocity.md","src/resources/skills/userinterface-wiki/rules/staging-dim-background.md","src/resources/skills/userinterface-wiki/rules/staging-one-focal-point.md","src/resources/skills/userinterface-wiki/rules/staging-z-index-hierarchy.md","src/resources/skills/userinterface-wiki/rules/timing-consistent.md","src/resources/skills/userinterface-wiki/rules/timing-no-entrance-context-menu.md","src/resources/skills/userinterface-wiki/rules/timing-under-300ms.md","src/resources/skills/userinterface-wiki/rules/transition-name-cleanup.md","src/resources/skills/userinterface-wiki/rules/transition-name-required.md","src/resources/skills/userinterface-wiki/rules/transition-name-unique.md","src/resources/skills/userinterface-wiki/rules/transition-over-js-library.md","src/resources/skills/userinterface-wiki/rules/transition-style-pseudo-elements.md","src/resources/skills/userinterface-wiki/rules/type-antialiased-on-retina.md","src/resources/skills/userinterface-wiki/rules/type-disambiguation-stylistic-set.md","src/resources/skills/userinterface-wiki/rules/type-font-display-swap.md","src/resources/skills/userinterface-wiki/rules/type-justify-with-hyphens.md","src/resources/skills/userinterface-wiki/rules/type-letter-spacing-uppercase.md","src/resources/skills/userinterface-wiki/rules/type-no-font-synthesis.md","src/resources/skills/userinterface-wiki/rules/type-oldstyle-nums-for-prose.md","src/resources/skills/userinterface-wiki/rules/type-opentype-contextual-alternates.md","src/resources/skills/userinterface-wiki/rules/type-optical-sizing-auto.md","src/resources/skills/userinterface-wiki/rules/type-proper-fractions.md","src/resources/skills/userinterface-wiki/rules/type-slashed-zero.md","src/resources/skills/userinterface-wiki/rules/type-tabular-nums-for-data.md","src/resources/skills/userinterface-wiki/rules/type-text-wrap-balance-headings.md","src/resources/skills/userinterface-wiki/rules/type-text-wrap-pretty.md","src/resources/skills/userinterface-wiki/rules/type-underline-offset.md","src/resources/skills/userinterface-wiki/rules/type-variable-weight-continuous.md","src/resources/skills/userinterface-wiki/rules/ux-aesthetic-usability.md","src/resources/skills/userinterface-wiki/rules/ux-cognitive-load-reduce.md","src/resources/skills/userinterface-wiki/rules/ux-common-region-boundaries.md","src/resources/skills/userinterface-wiki/rules/ux-doherty-perceived-speed.md","src/resources/skills/userinterface-wiki/rules/ux-doherty-under-400ms.md","src/resources/skills/userinterface-wiki/rules/ux-fitts-hit-area.md","src/resources/skills/userinterface-wiki/rules/ux-fitts-target-size.md","src/resources/skills/userinterface-wiki/rules/ux-goal-gradient-progress.md","src/resources/skills/userinterface-wiki/rules/ux-hicks-minimize-choices.md","src/resources/skills/userinterface-wiki/rules/ux-jakobs-familiar-patterns.md","src/resources/skills/userinterface-wiki/rules/ux-millers-chunking.md","src/resources/skills/userinterface-wiki/rules/ux-pareto-prioritize-features.md","src/resources/skills/userinterface-wiki/rules/ux-peak-end-finish-strong.md","src/resources/skills/userinterface-wiki/rules/ux-postels-accept-messy-input.md","src/resources/skills/userinterface-wiki/rules/ux-pragnanz-simplify.md","src/resources/skills/userinterface-wiki/rules/ux-progressive-disclosure.md","src/resources/skills/userinterface-wiki/rules/ux-proximity-grouping.md","src/resources/skills/userinterface-wiki/rules/ux-serial-position.md","src/resources/skills/userinterface-wiki/rules/ux-similarity-consistency.md","src/resources/skills/userinterface-wiki/rules/ux-teslers-complexity.md","src/resources/skills/userinterface-wiki/rules/ux-uniform-connectedness.md","src/resources/skills/userinterface-wiki/rules/ux-von-restorff-emphasis.md","src/resources/skills/userinterface-wiki/rules/ux-zeigarnik-show-incomplete.md","src/resources/skills/userinterface-wiki/rules/visual-animate-shadow-pseudo.md","src/resources/skills/userinterface-wiki/rules/visual-border-alpha-colors.md","src/resources/skills/userinterface-wiki/rules/visual-button-shadow-anatomy.md","src/resources/skills/userinterface-wiki/rules/visual-concentric-radius.md","src/resources/skills/userinterface-wiki/rules/visual-consistent-spacing-scale.md","src/resources/skills/userinterface-wiki/rules/visual-layered-shadows.md","src/resources/skills/userinterface-wiki/rules/visual-no-pure-black-shadow.md","src/resources/skills/userinterface-wiki/rules/visual-shadow-direction.md","src/resources/skills/userinterface-wiki/rules/visual-shadow-matches-elevation.md","src/resources/skills/userinterface-wiki/rules/weight-duration-matches-action.md","src/resources/skills/userinterface-wiki/rules/weight-match-action.md","src/resources/skills/verify-before-complete/SKILL.md","src/resources/skills/web-design-guidelines/SKILL.md","src/resources/skills/web-quality-audit/SKILL.md","src/resources/skills/write-docs/SKILL.md","src/resources/skills/write-milestone-brief/SKILL.md"],"skills":{"docs/agents/domain.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=docs%2Fagents%2Fdomain.md -->","docs/agents/issue-tracker.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=docs%2Fagents%2Fissue-tracker.md -->","docs/agents/triage-labels.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=docs%2Fagents%2Ftriage-labels.md -->","gsd-orchestrator/SKILL.md":"---\nname: gsd-orchestrator\ndescription: >\n  Build software products autonomously via GSD headless mode. Handles the full\n  lifecycle: write a spec, launch a build, poll for completion, handle blockers,\n  track costs, and verify the result. Use when asked to \"build something\",\n  \"create a project\", \"run gsd\", \"check build status\", or any task that\n  requires autonomous software development via subprocess.\nmetadata:\n  openclaw:\n    requires:\n      bins: [gsd]\n    install:\n      kind: node\n      package: gsd-pi\n      bins: [gsd]\n---\n\n<objective>\nYou are an autonomous agent that builds software by orchestrating GSD as a subprocess.\nGSD is a headless CLI that plans, codes, tests, and ships software from a spec.\nYou control it via shell commands, exit codes, and JSON output — no SDK, no RPC.\n</objective>\n\n<mental_model>\nGSD headless is a subprocess you launch and monitor. Think of it like a junior developer\nyou hand a spec to:\n\n1. You write the spec (what to build)\n2. You launch the build (`gsd headless ... new-milestone --context spec.md --auto`)\n3. You wait for it to finish (exit code tells you the outcome)\n4. You check the result (query state, inspect files, verify deliverables)\n5. If blocked, you intervene (steer, supply answers, or escalate)\n\nThe subprocess handles all planning, coding, testing, and git commits internally.\nYou never write application code yourself — GSD does that.\n</mental_model>\n\n<critical_rules>\n- **Flags before command.** `gsd headless [--flags] [command] [args]`. Flags after the command are ignored.\n- **Redirect stderr.** JSON output goes to stdout. Progress goes to stderr. Always `2>/dev/null` when parsing JSON.\n- **Check exit codes.** 0=success, 1=error, 10=blocked (needs you), 11=cancelled.\n- **Use `query` to poll.** Instant (~50ms), no LLM cost. Use it between steps, not `auto` for status.\n- **Budget awareness.** Track `cost.total` from query results. Set limits before launching long runs.\n- **One project directory per build.** Each GSD project needs its own directory with a `.gsd/` folder.\n</critical_rules>\n\n<routing>\nRoute based on what you need to do:\n\n**Build something from scratch:**\nRead `workflows/build-from-spec.md` — write spec, init directory, launch, monitor, verify.\n\n**Check on a running or completed build:**\nRead `workflows/monitor-and-poll.md` — query state, interpret phases, handle blockers.\n\n**Execute with fine-grained control:**\nRead `workflows/step-by-step.md` — run one unit at a time with decision points.\n\n**Understand the JSON output:**\nRead `references/json-result.md` — field reference for HeadlessJsonResult.\n\n**Pre-supply answers or secrets:**\nRead `references/answer-injection.md` — answer file schema and injection mechanism.\n\n**Look up a specific command:**\nRead `references/commands.md` — full command reference with flags and examples.\n</routing>\n\n<quick_reference>\n\n**Launch a full build (spec to working code):**\n```bash\nmkdir -p /tmp/my-project && cd /tmp/my-project && git init\ncat > spec.md << 'EOF'\n# Your Product Spec Here\nBuild a ...\nEOF\ngsd headless --output-format json --context spec.md new-milestone --auto 2>/dev/null\n```\n\n**Check project state (instant, free):**\n```bash\ncd /path/to/project\ngsd headless query | jq '{phase: .state.phase, progress: .state.progress, cost: .cost.total}'\n```\n\n**Resume work on an existing project:**\n```bash\ncd /path/to/project\ngsd headless --output-format json auto 2>/dev/null\n```\n\n**Run one step at a time:**\n```bash\nRESULT=$(gsd headless --output-format json next 2>/dev/null)\necho \"$RESULT\" | jq '{status: .status, phase: .phase, cost: .cost.total}'\n```\n\n</quick_reference>\n\n<exit_codes>\n| Code | Meaning | Your action |\n|------|---------|-------------|\n| `0`  | Success | Check deliverables, verify output, report completion |\n| `1`  | Error or timeout | Inspect stderr, check `.gsd/STATE.md`, retry or escalate |\n| `10` | Blocked | Query state for blocker details, steer around it or escalate to human |\n| `11` | Cancelled | Process was interrupted — resume with `--resume <sessionId>` or restart |\n</exit_codes>\n\n<project_structure>\nGSD creates and manages all state in `.gsd/`:\n```\n.gsd/\n  PROJECT.md          # What this project is\n  REQUIREMENTS.md     # Capability contract\n  DECISIONS.md        # Architectural decisions (append-only)\n  KNOWLEDGE.md        # Persistent project knowledge (manual rules, memory-projected patterns/lessons)\n  STATE.md            # Current phase and next action\n  milestones/\n    M001-xxxxx/\n      M001-xxxxx-CONTEXT.md    # Scope, constraints, assumptions\n      M001-xxxxx-ROADMAP.md    # Slices with checkboxes\n      M001-xxxxx-SUMMARY.md    # Completion summary\n      slices/S01/\n        S01-PLAN.md            # Tasks\n        S01-SUMMARY.md         # Slice summary\n        tasks/\n          T01-PLAN.md          # Individual task spec\n          T01-SUMMARY.md       # Task completion summary\n```\n\nState is derived from files on disk — checkboxes in ROADMAP.md and PLAN.md are the source of truth for completion. You never need to edit these files. GSD manages them. But you can read them to understand progress.\n</project_structure>\n\n<flags>\n| Flag | Description |\n|------|-------------|\n| `--output-format <fmt>` | `text` (default), `json` (structured result at exit), `stream-json` (JSONL events) |\n| `--json` | Alias for `--output-format stream-json` — JSONL event stream to stdout |\n| `--bare` | Skip CLAUDE.md, AGENTS.md, user settings, user skills. Use for CI/ecosystem runs. |\n| `--resume <id>` | Resume a prior headless session by its session ID |\n| `--timeout N` | Overall timeout in ms (default: 300000, use 0 to disable) |\n| `--model ID` | Override LLM model |\n| `--supervised` | Forward interactive UI requests to orchestrator via stdout/stdin |\n| `--response-timeout N` | Timeout (ms) for orchestrator response in supervised mode (default: 30000) |\n| `--answers <path>` | Pre-supply answers and secrets from JSON file |\n| `--events <types>` | Filter JSONL to specific event types (comma-separated, implies `--json`) |\n| `--verbose` | Show tool calls in progress output |\n| `--context <path>` | Spec file path for `new-milestone` (use `-` for stdin) |\n| `--context-text <text>` | Inline spec text for `new-milestone` |\n| `--auto` | Chain into auto-mode after `new-milestone` |\n</flags>\n\n<answer_injection>\nPre-supply answers and secrets for fully autonomous runs:\n\n```bash\ngsd headless --answers answers.json --output-format json auto 2>/dev/null\n```\n\n```json\n{\n  \"questions\": { \"question_id\": \"selected_option\" },\n  \"secrets\": { \"API_KEY\": \"sk-...\" },\n  \"defaults\": { \"strategy\": \"first_option\" }\n}\n```\n\n- **questions** — question ID to answer (string for single-select, string[] for multi-select)\n- **secrets** — env var to value, injected into child process environment\n- **defaults.strategy** — `\"first_option\"` (default) or `\"cancel\"` for unmatched questions\n\nSee `references/answer-injection.md` for the full mechanism.\n</answer_injection>\n\n<event_streaming>\nFor real-time monitoring, use JSONL event streaming:\n\n```bash\ngsd headless --json auto 2>/dev/null | while read -r line; do\n  TYPE=$(echo \"$line\" | jq -r '.type')\n  case \"$TYPE\" in\n    tool_execution_start) echo \"Tool: $(echo \"$line\" | jq -r '.toolName')\" ;;\n    extension_ui_request) echo \"GSD: $(echo \"$line\" | jq -r '.message // .title // empty')\" ;;\n    agent_end) echo \"Session ended\" ;;\n  esac\ndone\n```\n\nFilter to specific events: `--events agent_end,execution_complete,extension_ui_request`\n\nAvailable types: `agent_start`, `agent_end`, `tool_execution_start`, `tool_execution_end`,\n`tool_execution_update`, `extension_ui_request`, `message_start`, `message_end`,\n`message_update`, `turn_start`, `turn_end`, `cost_update`, `execution_complete`.\n</event_streaming>\n\n<all_commands>\n| Command | Purpose |\n|---------|---------|\n| `auto` | Run all queued units until milestone complete or blocked (default) |\n| `next` | Run exactly one unit, then exit |\n| `query` | Instant JSON snapshot — state, next dispatch, costs (no LLM, ~50ms) |\n| `new-milestone` | Create milestone from spec file |\n| `dispatch <phase>` | Force specific phase (research, plan, execute, complete, reassess, uat, replan) |\n| `stop` / `pause` | Control auto-mode |\n| `steer <desc>` | Hard-steer plan mid-execution |\n| `skip` / `undo` | Unit control |\n| `queue` | Queue/reorder milestones |\n| `history` | View execution history |\n| `doctor` | Health check + auto-fix |\n| `knowledge <rule\\|pattern\\|lesson>` | Add persistent project knowledge |\n\nSee `references/commands.md` for the complete reference.\n</all_commands>\n","packages/mcp-server/README.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=packages%2Fmcp-server%2FREADME.md -->","packages/rpc-client/README.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=packages%2Frpc-client%2FREADME.md -->","src/resources/extensions/gsd/docs/COORDINATION.md":"# Auto-mode coordination is single-host\n\nThe DB-backed coordination tables introduced by Phase B (`workers`,\n`milestone_leases`, `unit_dispatches`, `cancellation_requests`,\n`command_queue`) and the supporting `runtime_kv` table from Phase C all\nrely on **shared SQLite WAL on local disk**. They do not work across\nmachines.\n\n## Why single-host only\n\n- SQLite WAL coordination — the locking primitives that make\n  `claimMilestoneLease`, `recordDispatchClaim`, and `claimNextCommand`\n  atomic — is local-disk only. Network filesystems (NFS, SMB, S3FS) and\n  fuse mounts break the lock semantics that the WAL relies on.\n- Heartbeat TTL (`workers.last_heartbeat_at`) compares timestamps written\n  with SQLite wall-clock time (`datetime('now')`). Across machines without\n  wall-clock synchronization (for example NTP/chrony), TTL filtering can\n  produce phantom-active or premature-crashed verdicts. Monotonic clocks\n  are not used for these comparisons.\n- Fencing tokens (`milestone_leases.fencing_token`) are monotonically\n  ordered by SQL within a single transaction. Cross-host races could\n  produce duplicate tokens if two SQLite processes opened the same DB\n  on a network mount.\n\n## What does work\n\n- Multiple `gsd auto` worker processes on the **same machine**, sharing\n  the project's SQLite DB via WAL. The lease check refuses concurrent\n  claims on the same milestone; the dispatch ledger's partial unique\n  index refuses double-claims of the same unit.\n- A single `gsd auto` worker plus arbitrary read-only consumers\n  (dashboards, doctors) on the same machine.\n- Worktree-based parallelism on the same machine, where each worker\n  holds a different milestone lease.\n\n## Multi-host alternatives\n\nIf you need to coordinate `gsd auto` workers across machines, you need\na real coordinator: Postgres for the ledger + a leader-election service\n(etcd, Consul) for the leases. That's out of scope for these phases.\nThe schema and module shapes here would need a non-trivial backend\nswap before they could ride on top of either.\n","src/resources/extensions/gsd/docs/claude-marketplace-import.md":"# Claude Marketplace Import\n\nThis document describes the Claude marketplace import feature in GSD: what it reads, what it imports, what it persists, and what it does not translate into active GSD/Pi runtime behavior.\n\n---\n\n## What this feature does\n\nGSD can read Claude Code marketplace catalogs, inspect the plugins they reference, and import selected Claude skills into GSD/Pi while preserving Claude-style namespace identity.\n\nThe interactive entry point is:\n\n```text\n/gsd prefs import-claude\n```\n\nYou can also choose scope explicitly:\n\n```text\n/gsd prefs import-claude global\n/gsd prefs import-claude project\n```\n\n---\n\n## Claude Code model this feature follows\n\nAnthropic documents Claude marketplaces as sources users add with:\n\n```text\n/plugin marketplace add <github repo or local path>\n```\n\nA marketplace contains a catalog at:\n\n```text\n.claude-plugin/marketplace.json\n```\n\nAnthropic distinguishes between:\n\n- **Marketplace source** — where Claude fetches `marketplace.json`\n- **Plugin source** — where Claude fetches each plugin listed in that marketplace\n- **Installed plugin cache** — Claude copies installed plugin payloads into:\n\n```text\n~/.claude/plugins/cache\n```\n\nAnthropic also documents user-added marketplace sources under:\n\n```text\n~/.claude/plugins/marketplaces\n```\n\nGSD aligns its Claude import flow to that model.\n\n---\n\n## Where GSD looks\n\nFor Claude plugin and marketplace material, GSD prefers Claude-managed locations first:\n\n1. `~/.claude/plugins/marketplaces`\n2. `~/.claude/plugins/cache`\n3. `~/.claude/plugins`\n\nAfter that, GSD still allows local clone-style convenience paths such as sibling repos or `~/repos/...` paths. Those fallbacks remain supported for developer workflows, but they are not the primary Claude storage model.\n\n---\n\n## What GSD imports\n\n### Imported into GSD/Pi settings\n\n- Claude skills discovered directly from configured skill roots\n- Marketplace-derived skills\n\nImported marketplace skills preserve canonical namespace identity, for example:\n\n```text\npython3-development:stinkysnake\nscientific-method:experiment-protocol\n```\n\n### Discovered, modeled, and validated\n\n- Marketplace-derived agents\n\n### Discovered but not translated into active Pi-native runtime behavior\n\n- hooks\n- MCP server definitions\n- LSP server definitions\n- other plugin metadata that does not currently map directly into active GSD/Pi runtime surfaces\n\n---\n\n## Import flow\n\nThe import flow does the following:\n\n1. discover Claude skills and marketplace/plugin roots\n2. identify marketplace roots by checking for `.claude-plugin/marketplace.json`\n3. inspect discovered plugins and inventory their components\n4. let you select components to import\n5. validate the selection for canonical conflicts and ambiguity\n6. persist imported resources into GSD/Pi settings\n\n---\n\n## Namespace behavior\n\nGSD preserves Claude plugin namespace semantics rather than flattening plugin components into anonymous global names.\n\n### Canonical references\n\nCanonical references remain available for imported components:\n\n- skills: `plugin-name:skill-name`\n- agents: `plugin-name:agent-name`\n\n### Shorthand\n\nGSD supports shorthand lookup when it is unambiguous.\n\n### Local-first resolution\n\nWhen a namespaced component refers to another component by bare name, GSD tries the same plugin namespace first before broader lookup.\n\n---\n\n## Important safeguard: marketplace agent directories are not stored as package sources\n\nClaude plugin agent directories are markdown agent-definition directories, for example:\n\n```text\n.../plugins/python3-development/agents\n```\n\nGSD does **not** persist imported marketplace agent directories into:\n\n```json\nsettings.packages\n```\n\nThis is intentional.\n\n### Why\n\nPersisting an `.../agents` directory into `settings.packages` can cause Pi startup to treat that directory as an extension/package root. In real host validation, that produced extension loader failures such as:\n\n```text\nCannot find module '.../agents'\n```\n\nGSD now avoids writing those entries.\n\n---\n\n## Settings effects\n\n### Skills\n\nImported skills are persisted into Pi skill settings. Depending on the selection path, they may also be added to GSD preferences.\n\n### Marketplace agents\n\nMarketplace agents remain part of the import model and validation surface, but their `agents/` directories are not persisted as package roots.\n\n---\n\n## Diagnostics\n\nGSD distinguishes between:\n\n- **canonical conflicts** — hard errors\n- **shorthand overlaps** — warnings when canonical names remain distinct\n- **alias conflicts** — diagnostics for alias collisions or shadowing\n\nThis allows imported marketplace content to be validated without reporting valid overlap as fatal breakage.\n\n---\n\n## Verification status of this feature\n\nThis feature has been verified in three ways:\n\n1. **Contract/unit tests** for parsing, namespacing, resolution, diagnostics, and import behavior\n2. **Portable integration-style tests** using local or cloned marketplace fixtures\n3. **Real host validation** against the installed `gsd` binary and actual Claude-managed directories on the host machine\n\nReal host validation included:\n\n- clean startup of the installed `gsd` binary after fixing stale bad settings\n- successful invocation of an imported skill (`/stinkysnake`)\n- successful execution of `/gsd prefs import-claude global`\n- verification that imported marketplace agent directories were **not** reintroduced into `settings.packages`\n\n---\n\n## Current limitations\n\n- GSD does not yet translate every Claude plugin component type into active Pi-native runtime behavior\n- marketplace-derived agents are not persisted as package roots, by design\n- clone-style local fallbacks still exist for developer convenience, even though Claude-managed marketplace/plugin locations are preferred first\n\n---\n\n## References\n\n- Anthropic: Claude Code settings\n- Anthropic: Create and distribute a plugin marketplace\n- Anthropic: Plugins and plugin reference\n","src/resources/extensions/gsd/docs/preferences-reference.md":"# GSD Preferences Reference\n\nFull documentation for `~/.gsd/PREFERENCES.md` (global) and `.gsd/PREFERENCES.md` (project).\n\n---\n\n## Notes\n\n- Keep this skill-first.\n- Prefer explicit skill names or absolute paths.\n- Use absolute paths for personal/local skills when you want zero ambiguity.\n- These preferences guide which skills GSD should load and follow; they do not override higher-priority instructions in the current conversation.\n- For Claude marketplace/plugin import behavior, see `~/.gsd/agent/extensions/gsd/docs/claude-marketplace-import.md`.\n\n---\n\n## Semantics\n\n### Empty Arrays vs Omitted Fields\n\n**Empty arrays (`[]`) are equivalent to omitting the field entirely.** During validation, GSD deletes empty arrays from the preferences object (see `validatePreferences()` in `preferences.ts`):\n\n```typescript\nfor (const key of [\n  \"always_use_skills\",\n  \"prefer_skills\",\n  \"avoid_skills\",\n  \"custom_instructions\",\n] as const) {\n  if (validated[key] && validated[key]!.length === 0) {\n    delete validated[key];\n  }\n}\n```\n\nThese are functionally identical:\n\n```yaml\n# Explicit empty arrays — will be normalized away\nprefer_skills: []\navoid_skills: []\nskill_rules: []\n\n# Omitted entirely — same result\n# (just don't write these fields)\n```\n\n**Recommendation:** Omit fields you don't need. Empty arrays add noise with no effect.\n\n### Global vs Project Preferences\n\nPreferences are loaded from two locations and merged:\n\n1. **Global:** `~/.gsd/PREFERENCES.md` — applies to all projects\n2. **Project:** `.gsd/PREFERENCES.md` — applies to the current project only\n\n**Merge behavior** (see `mergePreferences()` in `preferences.ts`):\n\n- **Scalar fields** (`skill_discovery`, `budget_ceiling`, etc.): Project wins if defined, otherwise global. Uses nullish coalescing (`??`).\n- **Array fields** (`always_use_skills`, `prefer_skills`, etc.): Concatenated via `mergeStringLists()` (global first, then project).\n- **Object fields** (`models`, `git`, `auto_supervisor`): Shallow merge via spread operator `{ ...base, ...override }`.\n\nFor `models`, project settings override global at the phase level. If global has `planning: opus` and project has `planning: sonnet`, the project wins. But if project omits `research`, global's `research` setting is preserved.\n\n### Skill Discovery vs Skill Preferences\n\nThese are **separate concerns**:\n\n| Field                                                | What it controls                                          | Code reference                                           |\n| ---------------------------------------------------- | --------------------------------------------------------- | -------------------------------------------------------- |\n| `skill_discovery`                                    | **Whether** GSD looks for relevant skills during research | `resolveSkillDiscoveryMode()` in `preferences.ts`        |\n| `always_use_skills`, `prefer_skills`, `avoid_skills` | **Which** skills to use when they're found relevant       | `renderPreferencesForSystemPrompt()` in `preferences.ts` |\n\nSetting `prefer_skills: []` does **not** disable skill discovery — it just means you have no preference overrides. Use `skill_discovery: off` to disable discovery entirely.\n\n---\n\n## Field Guide\n\n- `version`: schema version. Start at `1`.\n\n- `mode`: workflow mode — `\"solo\"` or `\"team\"`. Sets sensible defaults for git and project settings based on your workflow. Mode defaults are the lowest priority layer — any explicit preference overrides them. Omit to configure everything manually.\n\n  | Setting                | `solo`       | `team`       |\n  | ---------------------- | ------------ | ------------ |\n  | `git.auto_push`        | `true`       | `false`      |\n  | `git.push_branches`    | `false`      | `true`       |\n  | `git.pre_merge_check`  | `false`      | `true`       |\n  | `git.merge_strategy`   | `\"squash\"`   | `\"squash\"`   |\n  | `git.isolation`        | `\"none\"`     | `\"none\"`     |\n  | `unique_milestone_ids` | `false`      | `true`       |\n\n  Quick setup: `/gsd mode` (global) or `/gsd mode project` (project-level).\n\n- `always_use_skills`: skills GSD should use whenever they are relevant.\n\n- `prefer_skills`: soft defaults GSD should prefer when relevant.\n\n- `avoid_skills`: skills GSD should avoid unless clearly needed.\n\n- `skill_rules`: situational rules with a human-readable `when` trigger and one or more of `use`, `prefer`, or `avoid`.\n\n- `custom_instructions`: extra durable instructions related to skill use. For operational project knowledge, use `.gsd/KNOWLEDGE.md` instead. Rules are file-canonical; patterns and lessons are persisted to the `memories` table and projected back into `KNOWLEDGE.md` on the next session start.\n\n- `language`: preferred response language for all GSD interactions. Accepts any language name or code — `\"Chinese\"`, `\"zh\"`, `\"German\"`, `\"de\"`, `\"日本語\"`, etc. When set, GSD injects \"Always respond in \\<language\\>\" into every agent's system prompt, including after `/clear`. Quickest way to set it: `/gsd language <name>`. To clear: `/gsd language off`.\n\n- `models`: per-stage model selection (applies to both auto-mode and guided-flow dispatches). Keys: `research`, `planning`, `discuss`, `execution`, `execution_simple`, `completion`, `validation`, `subagent`. Values can be:\n  - Simple string: `\"claude-sonnet-4-6\"` — single model, no fallbacks\n  - Provider-qualified string: `\"bedrock/claude-sonnet-4-6\"` — targets a specific provider when the same model ID exists across multiple providers\n  - Object with fallbacks: `{ model: \"claude-opus-4-6\", fallbacks: [\"glm-5\", \"minimax-m2.5\"] }` — tries fallbacks in order if primary fails\n  - Object with provider: `{ model: \"claude-opus-4-6\", provider: \"bedrock\" }` — explicit provider targeting in object format\n  - Omit a key to use whatever model is currently active (except `discuss` and `validation` which fall back to `planning` when unset). Fallbacks are tried when model switching fails (provider unavailable, rate limited, etc.).\n  - `discuss` — used for milestone/slice discussion (interactive context gathering). Falls back to `planning` if unset.\n  - `validation` — used for gate evaluation, roadmap reassessment, milestone validation, and doc rewrites. Falls back to `planning` if unset.\n\n- `skill_staleness_days`: number — skills unused for this many days get deprioritized during discovery. Set to `0` to disable staleness tracking. Default: `60`.\n\n- `skill_discovery`: controls how GSD discovers and applies skills during auto-mode. Valid values:\n  - `auto` — skills are found and applied automatically without prompting.\n  - `suggest` — (default) skills are identified during research but not installed automatically.\n  - `off` — skill discovery is disabled entirely.\n\n- `auto_supervisor`: configures the auto-mode supervisor that monitors agent progress and enforces timeouts. Keys:\n  - `model`: model ID to use for the supervisor process (defaults to the currently active model).\n  - `soft_timeout_minutes`: minutes before the supervisor issues a soft warning (default: 20).\n  - `idle_timeout_minutes`: minutes of inactivity before the supervisor intervenes (default: 10).\n  - `hard_timeout_minutes`: minutes before the supervisor forces termination (default: 30).\n\n- `min_request_interval_ms`: number — minimum integer milliseconds between auto-mode LLM request dispatches. Non-integer values are rounded down (e.g., `1000.9 → 1000`). Use this to proactively slow auto-mode on rate-limited providers and reduce 429 errors. Set to `0` to disable. Default: `0` (disabled).\n\n- `git`: configures GSD's git behavior. All fields are optional — omit any to use defaults. Keys:\n  - `auto_push`: boolean — automatically push commits to the remote after committing. Default: `false`.\n  - `push_branches`: boolean — push the milestone branch to the remote after commits. Default: `false`.\n  - `remote`: string — git remote name to push to. Default: `\"origin\"`.\n  - `snapshots`: boolean — create WIP snapshot commits (e.g. pre-dispatch and stale-uncommitted-changes safety commits emitted by the doctor). Set to `false` to suppress all doctor-initiated `gsd snapshot:` commits. Default: `true`.\n  - `pre_merge_check`: boolean or `\"auto\"` — run pre-merge checks before merging a worktree back to the integration branch. `true` always runs, `false` never runs, `\"auto\"` runs when CI is detected. Default: `\"auto\"`.\n  - `commit_type`: string — override the conventional commit type prefix. Must be one of: `feat`, `fix`, `refactor`, `docs`, `test`, `chore`, `perf`, `ci`, `build`, `style`. Default: inferred from diff content.\n  - `main_branch`: string — the primary branch name for new git repos (e.g., `\"main\"`, `\"master\"`, `\"trunk\"`). Also used by `getMainBranch()` as the preferred branch when auto-detection is ambiguous. Default: `\"main\"`.\n  - `merge_strategy`: `\"squash\"` or `\"merge\"` — controls how worktree branches are merged back. `\"squash\"` combines all commits into one; `\"merge\"` preserves individual commits. Default: `\"squash\"`.\n  - `isolation`: `\"none\"`, `\"worktree\"`, or `\"branch\"` — controls auto-mode git isolation strategy. `\"none\"` works directly on the current branch with no worktree or milestone branch (default, ideal for step-mode with hot reloads); `\"worktree\"` creates a milestone worktree for isolated work; `\"branch\"` works directly in the project root but creates a milestone branch (useful for submodule-heavy repos). `worktree` requires a committed `HEAD`; in a zero-commit repo, GSD temporarily treats it as `none` until the first commit exists. Default: `\"none\"`.\n  - `manage_gitignore`: boolean — when `false`, GSD will not touch `.gitignore` at all. Useful when your project has a strictly managed `.gitignore` and you don't want GSD adding entries. Default: `true`.\n  - `worktree_post_create`: string — script to run after a worktree is created (both auto-mode and manual `/worktree`). Receives `SOURCE_DIR` and `WORKTREE_DIR` as environment variables. Can be absolute or relative to project root. Runs with 30-second timeout. Failure is non-fatal (logged as warning). Default: none.\n  - `auto_pr`: boolean — automatically create a GitHub pull request after a milestone branch is merged. Requires `gh` CLI to be installed. Default: `false`.\n  - `pr_target_branch`: string — branch to target when `auto_pr` is enabled. Defaults to `main_branch` when omitted.\n  - **Deprecated:** `commit_docs` — no longer valid; `.gsd/` is always gitignored. Remove this setting.\n  - **Deprecated:** `merge_to_main` — no longer valid; milestone-level merge is always used. Remove this setting.\n\n- `workspace`: configures multi-repository parent workspaces. Keys:\n  - `mode`: `\"project\"` (default single-repo behavior) or `\"parent\"` (one `.gsd` controlling child repos).\n  - `repositories`: object map of repository IDs to config.\n    - Repository ID format: `^[A-Za-z0-9][A-Za-z0-9._-]*$`.\n    - Reserved ID: `project` is implicit and always maps to the project root; user-defined `workspace.repositories.project` is rejected.\n    - `path`: required relative path that must resolve within the project root (paths escaping via `..` are rejected).\n    - `role`: optional short description of what the repo owns.\n    - `verification`: optional array of verification commands for that repo.\n    - `commit_policy`: optional `\"auto\"` or `\"skip\"` to include or skip commit actions per repo.\n\n## Workspace Example\n\n```yaml\n---\nversion: 1\nworkspace:\n  mode: parent\n  repositories:\n    frontend:\n      path: frontend\n      role: web UI\n      verification:\n        - npm test\n        - npm run lint\n      commit_policy: auto\n    backend:\n      path: ./backend\n      role: API server\n      verification:\n        - go test ./...\n      commit_policy: auto\n---\n```\n\nThis config sets a parent workspace with two child repositories. The implicit `project` repository is always created for the project root and cannot be user-defined.\n\n- `unique_milestone_ids`: boolean — when `true`, generates milestone IDs in `M{seq}-{rand6}` format (e.g. `M001-eh88as`) instead of plain sequential `M001`. Prevents ID collisions in team workflows where multiple contributors create milestones concurrently. Both formats coexist — existing `M001`-style milestones remain valid. Default: `false`.\n\n- `budget_ceiling`: number — maximum dollar amount to spend on auto-mode. When reached, behavior is controlled by `budget_enforcement`. Default: no limit.\n\n- `budget_enforcement`: `\"warn\"`, `\"pause\"`, or `\"halt\"` — action taken when `budget_ceiling` is reached.\n  - `warn` — log a warning but continue execution.\n  - `pause` — pause auto-mode and wait for user confirmation.\n  - `halt` — stop auto-mode immediately.\n  - Default: `\"pause\"`.\n\n- `context_pause_threshold`: number (`0` or `1-100`) — live context window usage percentage at which auto-mode should pause to suggest checkpointing. Set to `0` to disable. Use whole percentages like `75`, not fractional ratios like `0.75`. Default: `0` (disabled).\n\n- `token_profile`: `\"budget\"`, `\"balanced\"`, `\"quality\"`, or `\"burn-max\"` — coordinates model selection, phase skipping, and context compression. `budget` skips research/reassessment and uses cheaper models; `balanced` (default) skips research/reassessment to reduce token burn; `quality` prefers higher-quality models; `burn-max` keeps full-context defaults, disables downgrade routing, and keeps phase skips off.\n\n- `planning_depth`: `\"light\"` or `\"deep\"` — controls project-level discovery before milestone planning. `\"light\"` is the default milestone discussion flow. `\"deep\"` runs workflow preferences, project discussion, requirements discussion, a research-decision gate, and optional project research before milestone planning. Enable it with `/gsd new-project --deep`, `/gsd new-milestone --deep`, or by setting `planning_depth: deep` in project-local `.gsd/PREFERENCES.md`. Global `~/.gsd/PREFERENCES.md` does not opt every fresh repo into deep mode. Deep mode writes `.gsd/PROJECT.md`, `.gsd/REQUIREMENTS.md`, `.gsd/runtime/research-decision.json`, and, when research is approved, `.gsd/research/STACK.md`, `FEATURES.md`, `ARCHITECTURE.md`, and `PITFALLS.md`.\n\n- `phases`: fine-grained control over which phases run. Usually set by `token_profile`, but can be overridden. Keys:\n  - `skip_research`: boolean — skip milestone-level research. Default: `false`.\n  - `reassess_after_slice`: boolean — run a dedicated roadmap-reassessment unit after each completed slice. Default: `false` (per ADR-003 §4). The plan-slice agent for the next slice performs JIT reassessment via a prompt preamble at zero additional token cost; a dedicated reassess session is opt-in. Set to `true` (e.g. via the `burn-max` profile) if you want the explicit session.\n  - `skip_reassess`: boolean — force-disable roadmap reassessment even if `reassess_after_slice` is enabled. Default: `false`.\n  - `skip_slice_research`: boolean — skip per-slice research. Default: `false`.\n\n- `reactive_execution`: controls automatic parallel task dispatch inside a slice. Reactive execution is enabled by default when omitted; set `enabled: false` to opt out. With default-on behavior, GSD only attempts a reactive batch when at least three ready tasks are available and the task-plan IO graph is non-ambiguous. If you set `enabled: true` explicitly, GSD uses the earlier opt-in threshold of two ready tasks. Keys:\n  - `enabled`: boolean — set `false` to force sequential task execution. Default: `true`.\n  - `max_parallel`: number — maximum tasks to dispatch in one batch, range `1`-`8`. Default: `2`.\n  - `isolation_mode`: `\"same-tree\"` — currently the only supported value.\n  - `subagent_model`: string — optional model override for reactive task subagents. Falls back to the `models.subagent` routing when omitted.\n\n- `remote_questions`: route interactive questions to Slack/Discord for headless auto-mode. Keys:\n  - `channel`: `\"slack\"` or `\"discord\"` — channel type.\n  - `channel_id`: string or number — channel ID.\n  - `timeout_minutes`: number — question timeout in minutes (clamped 1-30).\n  - `poll_interval_seconds`: number — poll interval in seconds (clamped 2-30).\n\n- `notifications`: configures desktop notification behavior during auto-mode. Keys:\n  - `enabled`: boolean — master toggle for all notifications. Default: `true`.\n  - `on_complete`: boolean — notify when a unit completes. Default: `true`.\n  - `on_error`: boolean — notify on errors. Default: `true`.\n  - `on_budget`: boolean — notify when budget thresholds are reached. Default: `true`.\n  - `on_milestone`: boolean — notify when a milestone finishes. Default: `true`.\n  - `on_attention`: boolean — notify when manual attention is needed. Default: `true`.\n  - Terminal auto-loop errors persist an `activity/*-auto-crash-note.json` file with error/session metadata; when available, the error notification includes the crash-note path and instructs resuming with `/gsd auto`.\n\n- `cmux`: configures cmux terminal integration when GSD is running inside a cmux workspace. Keys:\n  - `enabled`: boolean — master toggle for cmux integration. Default: `false`.\n  - `notifications`: boolean — route desktop notifications through cmux. Default: `true` when enabled.\n  - `sidebar`: boolean — publish status, progress, and log metadata to the cmux sidebar. Default: `true` when enabled.\n  - `splits`: boolean — run supported subagent work in visible cmux splits. Default: `false`.\n  - `browser`: boolean — reserve the future browser integration flag. Default: `false`.\n\n- `dynamic_routing`: configures the dynamic model router that adjusts model selection based on task complexity. Keys:\n  - `enabled`: boolean — enable dynamic routing. Default: `false`.\n  - `tier_models`: object — model overrides per complexity tier. Keys: `light`, `standard`, `heavy`. Values are model ID strings.\n  - `escalate_on_failure`: boolean — escalate to a higher-tier model when the current one fails. Default: `true`.\n  - `budget_pressure`: boolean — downgrade model tier when budget is under pressure. Default: `true`.\n  - `cross_provider`: boolean — allow routing across different providers. Default: `true`.\n  - `hooks`: boolean — enable routing hooks. Default: `true`.\n  - `capability_routing`: boolean — enable capability-profile scoring for model selection within a tier. Requires `enabled: true`. Default: `false`.\n\n- `disabled_model_providers`: string[] — provider IDs to hide from model selection and routing (for example `[\"google-gemini-cli\"]`). This only affects model availability (`/model`, auto-model selection, routing); it does not disable tool auth flows like `google_search`.\n\n- `uok`: Unified Orchestration Kernel controls. Keys:\n  - `enabled`: boolean — enable kernel wrappers and contract observers. Default: `true`.\n  - `legacy_fallback.enabled`: boolean — emergency release fallback that forces legacy orchestration behavior even when `uok.enabled` is `true`. Default: `false`.\n    - Runtime override: set `GSD_UOK_FORCE_LEGACY=1` (or `GSD_UOK_LEGACY_FALLBACK=1`) to force legacy behavior for the current process.\n  - `gates.enabled`: boolean — route checks through the unified gate runner and persist `gate_runs`. Default: `true`.\n  - `model_policy.enabled`: boolean — enforce policy filtering before model capability scoring. Default: `true`.\n  - `execution_graph.enabled`: boolean — enable DAG scheduler facade/adapters for execution. Default: `true`.\n  - `gitops.enabled`: boolean — persist turn-level git transaction records. Default: `true`.\n  - `gitops.turn_action`: `\"commit\"` | `\"snapshot\"` | `\"status-only\"` — turn transaction mode. Default: `\"commit\"` (per-task atomic commits).\n  - `gitops.turn_push`: boolean — whether turn transactions should include push intent metadata. Default: `false`.\n  - `audit_unified.enabled`: boolean — dual-write unified audit envelope events. Default: `true`.\n  - `plan_v2.enabled`: boolean — enable bounded clarify/research/draft/compile planning flow. Default: `true`.\n\n- `context_management`: configures context hygiene for auto-mode sessions. Keys:\n  - `observation_masking`: boolean — mask old tool results to reduce context bloat. Default: `true`.\n  - `observation_mask_turns`: number — keep this many recent turns verbatim (1-50). Default: `8`.\n  - `compaction_threshold_percent`: number — trigger compaction at this % of context window (0.5-0.95). Lower values fire compaction earlier, reducing drift. Default: `0.60`.\n  - `tool_result_max_chars`: number — max chars per tool result in GSD sessions (200-10000). Default: `800`.\n\n- `auto_visualize`: boolean — show a visualizer hint after each milestone completion in auto-mode. Default: `false`.\n\n- `auto_report`: boolean — generate an HTML report snapshot after each milestone completion. Default: `true`.\n\n- `search_provider`: `\"brave\"`, `\"tavily\"`, `\"ollama\"`, `\"native\"`, or `\"auto\"` — selects the search backend for research phases. `\"native\"` forces Anthropic's built-in web search only; provider values force that backend and disable native search; `\"auto\"` uses the default heuristic. Default: `\"auto\"`.\n\n- `context_selection`: `\"full\"` or `\"smart\"` — controls how files are inlined into context. `\"full\"` inlines entire files; `\"smart\"` uses semantic chunking to include only the most relevant sections. Default is derived from `token_profile`.\n\n- `parallel`: configures parallel orchestration for running multiple slices concurrently. Keys:\n  - `enabled`: boolean — enable parallel execution. Default: `false`.\n  - `max_workers`: number — maximum concurrent workers (1-4). Default: `2`.\n  - `budget_ceiling`: number — optional per-parallel-run budget ceiling.\n  - `merge_strategy`: `\"per-slice\"` or `\"per-milestone\"` — when to merge worktree results back. Default: `\"per-milestone\"`.\n  - `auto_merge`: `\"auto\"`, `\"confirm\"`, or `\"manual\"` — merge behavior after completion. `\"auto\"` merges immediately; `\"confirm\"` asks first; `\"manual\"` leaves branches for you. Default: `\"confirm\"`.\n  - `worker_model`: string — optional model override for parallel milestone workers. When set, workers use this model (e.g. `\"claude-haiku-4-5\"`) instead of inheriting the coordinator's model. Useful for cost savings on execution-heavy milestones.\n\n- `workspace`: repository-scoping for parent/multi-repo workspaces. Keys:\n  - `mode`: `\"project\"` | `\"parent\"` — enables single-repo (default) or parent workspace behavior.\n  - `repositories`: map of repository IDs to repository config:\n    - `path`: string (required) — path relative to project root.\n    - `role`: string (optional) — informational role label.\n    - `verification`: string[] (optional) — repository-specific verification commands used when global `verification_commands` is not set.\n    - `commit_policy`: `\"auto\"` | `\"skip\"` (optional) — per-repository closeout commit behavior.\n  - `project` is always an implicit repository target mapped to the project root for backward compatibility.\n  - Plan/task `targetRepositories` defaults to `[\"project\"]` when omitted.\n\n- `verification_commands`: string[] — shell commands to run as verification after task execution (e.g., `[\"npm test\", \"npm run lint\"]`). Commands run in order; if any fails, the task is marked as needing fixes.\n\n- `verification_auto_fix`: boolean — when `true`, automatically attempt to fix verification failures instead of just reporting them. Default: `false`.\n\n- `verification_max_retries`: number — maximum number of fix-and-retry cycles for verification failures. Default: `0` (no retries).\n\n- `per_unit_cost_cap_usd`: number — per-unit retry cost ceiling in USD for verification retries. Must be a positive finite number when set; invalid values are rejected during preference validation. Default: `5.0`. During auto-verification and artifact-retry flows, auto-mode pauses when the current unit reaches this cap or when current unit cost spikes to at least `3.0x` the rolling average.\n\n- `uat_dispatch`: boolean — when `true`, enables UAT (User Acceptance Testing) dispatch mode. Default: `false`.\n\n- `post_unit_hooks`: array — hooks that fire after a unit completes. Each entry has:\n  - `name`: string — unique hook identifier.\n  - `after`: string[] — unit types that trigger this hook (e.g., `[\"execute-task\"]`).\n  - `prompt`: string — prompt sent to the LLM. Supports `{milestoneId}`, `{sliceId}`, `{taskId}` substitutions.\n  - `max_cycles`: number — max times this hook fires per trigger (default: 1, max: 10).\n  - `model`: string — optional model override.\n  - `artifact`: string — expected output file name (relative to task/slice dir). Hook is skipped if file already exists (idempotent).\n  - `retry_on`: string — if this file is produced instead of the artifact, re-run the trigger unit then re-run hooks.\n  - `agent`: string — agent definition file to use for hook execution.\n  - `enabled`: boolean — toggle without removing (default: `true`).\n\n- `pre_dispatch_hooks`: array — hooks that fire before a unit is dispatched. Each entry has:\n  - `name`: string — unique hook identifier.\n  - `before`: string[] — unit types to intercept.\n  - `action`: `\"modify\"`, `\"skip\"`, or `\"replace\"` — what to do with the unit.\n  - `prepend`: string — text prepended to unit prompt (for `\"modify\"` action).\n  - `append`: string — text appended to unit prompt (for `\"modify\"` action).\n  - `prompt`: string — replacement prompt (for `\"replace\"` action; required when action is `\"replace\"`).\n  - `unit_type`: string — override unit type label (for `\"replace\"` action).\n  - `skip_if`: string — for `\"skip\"` action: only skip if this file exists (relative to unit dir).\n  - `model`: string — optional model override when this hook fires.\n  - `enabled`: boolean — toggle without removing (default: `true`).\n\n  **Action validation:**\n  - `\"modify\"` requires at least one of `prepend` or `append`.\n  - `\"replace\"` requires `prompt`.\n  - `\"skip\"` is valid with no additional fields.\n\n  **Known unit types for `before`/`after`:** `research-milestone`, `plan-milestone`, `research-slice`, `plan-slice`, `execute-task`, `complete-slice`, `replan-slice`, `reassess-roadmap`, `run-uat`.\n\n- `experimental`: opt-in experimental features. All features here are **off by default** — you must explicitly set each one to `true` to enable it. Features in this block may change or be removed without a deprecation cycle while in experimental status. Keys:\n  - `rtk`: boolean — enable RTK (Real-Time Kompression) shell-command compression. When enabled, GSD wraps shell commands through the RTK binary to reduce token usage during command execution. RTK is downloaded automatically on first use if not already installed. **Default: `false`** (opt-in required). Set `GSD_RTK_DISABLED=1` in the environment to force-disable regardless of this preference.\n\n---\n\n## Best Practices\n\n- Keep `always_use_skills` short.\n- Use `skill_rules` for situational routing, not broad personality preferences.\n- Prefer skill names for stable built-in skills.\n- Prefer absolute paths for local personal skills.\n- **Omit fields you don't need** — empty arrays add noise with no effect.\n\n---\n\n## Workflow Mode Examples\n\n**Solo developer — auto-push, simple IDs:**\n\n```yaml\n---\nversion: 1\nmode: solo\n---\n```\n\nEquivalent to setting `git.auto_push: true`, `git.push_branches: false`, `git.pre_merge_check: false`, `git.merge_strategy: squash`, `git.isolation: none`, `unique_milestone_ids: false`.\n\n**Team — unique IDs, push branches, pre-merge checks:**\n\n```yaml\n---\nversion: 1\nmode: team\n---\n```\n\nEquivalent to setting `git.auto_push: false`, `git.push_branches: true`, `git.pre_merge_check: true`, `git.merge_strategy: squash`, `git.isolation: none`, `unique_milestone_ids: true`.\n\n**Mode with overrides — team mode but with auto-push:**\n\n```yaml\n---\nversion: 1\nmode: team\ngit:\n  auto_push: true\n---\n```\n\nGets all team defaults except `auto_push`, which is explicitly overridden to `true`. Any explicit setting always wins over the mode default.\n\n---\n\n## Minimal Example\n\nThe cleanest preferences file only specifies what you actually want:\n\n```yaml\n---\nversion: 1\nalways_use_skills:\n  - debug-like-expert\nskill_discovery: suggest\nmodels:\n  planning: claude-opus-4-6\n  execution: claude-sonnet-4-6\n---\n```\n\nEverything else uses defaults. No `prefer_skills: []`, no `avoid_skills: []`, no `auto_supervisor: {}` — those are just noise.\n\n---\n\n## Models Example\n\n```yaml\n---\nversion: 1\nmodels:\n  research: claude-sonnet-4-6\n  planning: claude-opus-4-6\n  execution: claude-sonnet-4-6\n  completion: claude-sonnet-4-6\n---\n```\n\nOpus for planning (where architectural decisions matter most), Sonnet for everything else (faster, cheaper). Omit any key to use the currently selected model.\n\n## Models with Fallbacks Example\n\n```yaml\n---\nversion: 1\nmodels:\n  research:\n    model: openrouter/deepseek/deepseek-r1\n    fallbacks:\n      - openrouter/minimax/minimax-m2.5\n  planning:\n    model: claude-opus-4-6\n    fallbacks:\n      - openrouter/z-ai/glm-5\n      - openrouter/moonshotai/kimi-k2.5\n  execution:\n    model: openrouter/z-ai/glm-5\n    fallbacks:\n      - openrouter/minimax/minimax-m2.5\n  completion: openrouter/minimax/minimax-m2.5\n---\n```\n\nWhen a model fails to switch (provider unavailable, rate limited, credits exhausted), GSD automatically tries the next model in the `fallbacks` list. This ensures auto-mode continues even when your preferred provider hits limits.\n\n## Provider Targeting\n\nWhen the same model ID exists across multiple providers (e.g., `claude-sonnet-4-6` on both Anthropic and Bedrock), use the `provider/model` format or the `provider` field to target a specific one:\n\n```yaml\n---\nversion: 1\nmodels:\n  # String format: provider/model\n  research: bedrock/claude-sonnet-4-6\n  planning: anthropic/claude-opus-4-6\n\n  # Object format: explicit provider field\n  execution:\n    model: claude-sonnet-4-6\n    provider: bedrock\n    fallbacks:\n      - anthropic/claude-sonnet-4-6\n---\n```\n\nIf you use a bare model ID (no provider prefix) and it exists in multiple providers, GSD will warn you and resolve to the first available match. Use `provider/model` format to avoid ambiguity.\n\n**Cost-optimized example** — use cheap models with expensive ones as fallback for critical phases:\n\n```yaml\n---\nversion: 1\nmodels:\n  research: openrouter/deepseek/deepseek-r1 # $0.28/$0.42 per 1M tokens\n  planning:\n    model: claude-opus-4-6 # $5/$25 — best for architecture\n    fallbacks:\n      - openrouter/z-ai/glm-5 # $1/$3.20 — strong alternative\n  execution: openrouter/minimax/minimax-m2.5 # $0.30/$1.20 — cheapest quality\n  completion: openrouter/minimax/minimax-m2.5\n---\n```\n\n---\n\n## Example Variations\n\n**Minimal — always load a UAT skill and route Clerk tasks:**\n\n```yaml\n---\nversion: 1\nalways_use_skills:\n  - /Users/you/.claude/skills/verify-uat\nskill_rules:\n  - when: finishing implementation and human judgment matters\n    use:\n      - /Users/you/.claude/skills/verify-uat\n---\n```\n\n**Richer routing — prefer cleanup and authentication skills:**\n\n```yaml\n---\nversion: 1\nprefer_skills:\n  - commit-ignore\nskill_rules:\n  - when: task involves Clerk authentication\n    use:\n      - clerk\n      - clerk-setup\n  - when: the user is looking for installable capability rather than implementation\n    prefer:\n      - find-skills\n---\n```\n\n---\n\n## Git Preferences Example\n\n```yaml\n---\nversion: 1\ngit:\n  auto_push: true\n  push_branches: true\n  remote: origin\n  snapshots: true\n  pre_merge_check: auto\n  commit_type: feat\n---\n```\n\nAll git fields are optional. Omit any field to use the default behavior. Project-level preferences override global preferences on a per-field basis.\n\n---\n\n## Budget & Cost Control Example\n\n```yaml\n---\nversion: 1\nbudget_ceiling: 10.00\nbudget_enforcement: pause\ncontext_pause_threshold: 80\n---\n```\n\nSets a $10 budget ceiling. Auto-mode pauses when the ceiling is reached. Context window pauses at 80% usage for checkpointing.\n\n---\n\n## Notifications Example\n\n```yaml\n---\nversion: 1\nnotifications:\n  enabled: true\n  on_complete: false\n  on_error: true\n  on_budget: true\n  on_milestone: true\n  on_attention: true\n---\n```\n\nDisables per-unit completion notifications (noisy in long runs) while keeping error, budget, milestone, and attention notifications enabled.\n\n---\n\n## cmux Example\n\n```yaml\n---\nversion: 1\ncmux:\n  enabled: true\n  notifications: true\n  sidebar: true\n  splits: true\n  browser: false\n---\n```\n\nEnables cmux-aware notifications, sidebar metadata, and visible subagent splits when GSD is running inside a cmux terminal.\n\n---\n\n## Post-Unit Hooks Example\n\n```yaml\n---\nversion: 1\npost_unit_hooks:\n  - name: code-review\n    after:\n      - execute-task\n    prompt: \"Review the code changes in {sliceId}/{taskId} for quality, security, and test coverage.\"\n    max_cycles: 1\n    artifact: REVIEW.md\n---\n```\n\nRuns an automated code review after each task execution. Skips if `REVIEW.md` already exists (idempotent).\n\n---\n\n## Pre-Dispatch Hooks Examples\n\n**Modify — inject instructions before every task:**\n\n```yaml\n---\nversion: 1\npre_dispatch_hooks:\n  - name: enforce-standards\n    before:\n      - execute-task\n    action: modify\n    prepend: \"Follow our TypeScript coding standards and always run linting.\"\n---\n```\n\n**Skip — skip per-slice research when a research file already exists:**\n\n```yaml\n---\nversion: 1\npre_dispatch_hooks:\n  - name: skip-existing-research\n    before:\n      - research-slice\n    action: skip\n    skip_if: RESEARCH.md\n---\n```\n\n**Replace — substitute a custom prompt for task execution:**\n\n```yaml\n---\nversion: 1\npre_dispatch_hooks:\n  - name: tdd-execute\n    before:\n      - execute-task\n    action: replace\n    prompt: \"Implement the task using strict TDD. Write failing tests first, then implement, then refactor.\"\n    model: claude-opus-4-6\n---\n```\n\n---\n\n## Token Profile & Phases Example\n\n```yaml\n---\nversion: 1\ntoken_profile: budget\nphases:\n  skip_research: true\n  skip_reassess: true\n  skip_slice_research: false\n---\n```\n\nUses the `budget` profile to minimize token usage, with explicit override to keep slice-level research enabled.\n\n---\n\n## Remote Questions Example\n\n```yaml\n---\nversion: 1\nremote_questions:\n  channel: slack\n  channel_id: \"C0123456789\"\n  timeout_minutes: 15\n  poll_interval_seconds: 10\n---\n```\n\nRoutes interactive questions to a Slack channel for headless auto-mode sessions. Questions time out after 15 minutes if unanswered.\n\n---\n\n## Dynamic Routing Example\n\n```yaml\n---\nversion: 1\ndynamic_routing:\n  enabled: true\n  tier_models:\n    light: openrouter/minimax/minimax-m2.5\n    standard: claude-sonnet-4-6\n    heavy: claude-opus-4-6\n  escalate_on_failure: true\n  budget_pressure: true\n---\n```\n\nAutomatically selects model tier based on task complexity. Simple tasks use the `light` model, complex tasks escalate to `heavy`. Under budget pressure, tasks are routed to cheaper tiers.\n\n---\n\n## Parallel Execution Example\n\n```yaml\n---\nversion: 1\nparallel:\n  enabled: true\n  max_workers: 3\n  merge_strategy: per-milestone\n  auto_merge: confirm\n---\n```\n\nRuns up to 3 slices concurrently in separate worktrees. Results are merged per-milestone with user confirmation.\n\n---\n\n## Verification Example\n\n```yaml\n---\nversion: 1\nverification_commands:\n  - npm test\n  - npm run lint\n  - npm run typecheck\nverification_auto_fix: true\nverification_max_retries: 2\n---\n```\n\nRuns test, lint, and typecheck after each task. On failure, auto-fix is attempted up to 2 times before reporting the issue.\n\n## Experimental Features Example\n\n```yaml\n---\nversion: 1\nexperimental:\n  rtk: true\n---\n```\n\nOpts in to RTK shell-command compression. RTK is downloaded automatically on first use. Set `GSD_RTK_DISABLED=1` to force-disable at the environment level regardless of this setting.\n","src/resources/extensions/gsd/prompts/heal-skill.md":"## Skill Heal Analysis\n\nAnalyze the just-completed unit ({{unitId}}) for skill drift.\n\n### Steps\n\n1. **Identify loaded skill**: Check which SKILL.md file was read during this unit by examining recent tool calls. If no skill was explicitly loaded (no `read` call to a SKILL.md path), write \"No skill loaded — skipping heal analysis\" to {{healArtifact}} and stop.\n\n2. **Read the skill**: Load the SKILL.md that was used during this unit.\n\n3. **Compare execution to skill guidance**: Review what the agent actually did vs what the skill recommended. Look for:\n   - API patterns the skill recommended that the agent did differently\n   - Error handling approaches the skill specified but the agent bypassed\n   - Conventions the skill documented that the agent ignored\n   - Outdated instructions in the skill that caused errors, retries, or workarounds\n   - Commands or tools the skill referenced that no longer exist or have changed\n\n4. **Assess drift severity**:\n   - **None**: Agent followed skill correctly → write \"No drift detected\" to {{healArtifact}} and stop\n   - **Minor**: Agent found a better approach but skill isn't wrong → append a note to `.gsd/KNOWLEDGE.md` and stop\n   - **Significant**: Skill has outdated or incorrect guidance → continue to step 5\n\n5. **If significant drift found**, append a heal suggestion to `.gsd/skill-review-queue.md`:\n\n```markdown\n### {{skillName}} (flagged {{date}})\n- **Unit:** {{unitId}}\n- **Issue:** {1-2 sentence description of what was wrong}\n- **Root cause:** {outdated API / incorrect pattern / missing context / etc.}\n- **Discovery method:** {how the agent discovered the skill was wrong — error message, trial and error, docs lookup, etc.}\n- **Proposed fix:**\n  - File: {relative path to the file in the skill directory}\n  - Section: {section heading or line range}\n  - Current: {quote the incorrect/outdated text}\n  - Suggested: {the corrected text}\n- **Action:** [ ] Reviewed [ ] Updated [ ] Dismissed\n```\n\nThen write a brief summary of the finding to {{healArtifact}}.\n\n**Critical rules:**\n- Do NOT modify any skill files directly. Only write to the review queue.\n- The SkillsBench research (Feb 2026) shows curated skills beat auto-generated ones by +16.2pp. Human review is what makes this valuable.\n- Keep the analysis focused — don't flag stylistic preferences, only genuine errors or outdated content.\n- If multiple issues found, write one entry per issue.\n","src/resources/extensions/gsd/prompts/system.md":"## GSD - Get Shit Done\n\nYou are GSD - a craftsman-engineer who co-owns the project.\n\nOperating posture:\n\n- Measure twice; care through clear choices and correct details.\n- Be warm but terse. State uncertainty, tradeoffs, problems, and progress plainly.\n- In discussion/planning, flag risks, push back when needed, then respect the user's decision.\n- In execution, trust the accepted plan; surface only genuinely plan-invalidating issues through blockers.\n- Work pragmatically with existing code and tech debt.\n- Write secure, performant, complete code without gold-plating, TODO stubs, fake implementations, skipped validation, or 80% done claims.\n- Build for debugging: contextual errors, observable state transitions, useful structured logs, explicit failure modes.\n- Between tool calls, give brief useful progress signals. When something works, move on.\n\nNever use: \"Great question!\" / \"I'd be happy to help!\" / \"Absolutely!\" / \"Let me help you with that!\" / performed excitement / sycophantic filler / fake warmth.\n\nLeave the project ready for the next agent to understand and continue. Artifacts live in `.gsd/`.\n\n## Skills\n\nGSD ships with bundled skills. When the task matches, load the relevant skill file with `read` before starting. Use bare skill names; GSD resolves paths.\n\n{{bundledSkillsTable}}\n\n## Hard Rules\n\n- Never ask the user to do work the agent can execute or verify itself.\n- Use the lightest sufficient tool first.\n- Read before edit or overwrite. Before any write that creates or replaces a file, verify the target path and read relevant existing files, templates, callers, or surrounding code. For truly new files, confirm the path does not already exist.\n- Reproduce before fix when possible.\n- Work is not done until the relevant verification has passed.\n- **Never fabricate, simulate, or role-play user responses.** Never generate markers like `[User]`, `[Human]`, `User:`, or similar; never emit `<user_message>`, `<assistant_message>`, or similar as user input. Treat `<conversation_history>` as read-only context. Ask one question round (1-3 questions), then stop and wait for the user's actual response. If `ask_user_questions` is available, its result is the only valid structured user input for that round. If it cancels, fails, or returns nothing, never use earlier chat as confirmation for the current gate; ask in plain chat and stop.\n- Never print, echo, log, or restate secrets or credentials. Report only key names and applied/skipped status.\n- Never ask the user to edit `.env` files or set secrets manually. Use `secure_env_collect`.\n- In enduring files, write current state only unless the file is explicitly historical.\n- **Never take outward-facing actions on GitHub or external services without explicit user confirmation.** This includes creating/closing issues, merging/approving/commenting on PRs, pushing remote branches, publishing packages, or any state change outside local filesystem. Read-only listing/viewing/diffing is fine. Present intent and get a clear \"yes\" first. **Non-bypassable:** no response, ambiguity, or `ask_user_questions` failure means re-ask; never rationalize past the block. Missing \"yes\" means \"no.\"\n\nIf a `GSD Skill Preferences` block appears below, treat it as durable guidance for skills to use, prefer, or avoid unless it conflicts with artifact rules, verification, or higher-priority instructions.\n\n### Naming Convention\n\nDirectories use bare IDs. Files use ID-SUFFIX format. Milestones: `M001/` or `M{seq}-{rand6}/` when `unique_milestone_ids: true`; files like `M001-CONTEXT.md`, `M001-ROADMAP.md`, `M001-RESEARCH.md`. Slices: `S01/` with `S01-PLAN.md`, `S01-RESEARCH.md`, `S01-SUMMARY.md`, `S01-UAT.md`. Tasks: `T01-PLAN.md`, `T01-SUMMARY.md`. Titles live inside content, not names.\n\n### Directory Structure\n\n```\n.gsd/\n  PROJECT.md, REQUIREMENTS.md, DECISIONS.md, KNOWLEDGE.md, CODEBASE.md, OVERRIDES.md, QUEUE.md, STATE.md\n  runtime/, activity/, worktrees/\n  milestones/M001/\n    M001-CONTEXT.md, M001-RESEARCH.md, M001-ROADMAP.md, M001-SUMMARY.md\n    slices/S01/\n      S01-CONTEXT.md, S01-RESEARCH.md, S01-PLAN.md, S01-SUMMARY.md, S01-UAT.md\n      tasks/T01-PLAN.md, tasks/T01-SUMMARY.md\n```\n\n`runtime/`, `activity/`, `worktrees/`, and `STATE.md` are system-managed. `PROJECT.md` is current state; `REQUIREMENTS.md` is the active capability contract; `DECISIONS.md` and `KNOWLEDGE.md` are append-only; `CODEBASE.md` is an auto-refreshed codebase map.\n\n### Isolation Model\n\nAuto-mode isolation is configured in `.gsd/PREFERENCES.md` under `git.isolation`: **none** works on the current branch; **worktree** uses `.gsd/worktrees/<MID>/` on `milestone/<MID>` and merges back on completion; **branch** uses `milestone/<MID>` in-place. Slices commit sequentially on the active branch; no per-slice branches.\n\n**If you are executing in auto-mode, your working directory is shown in the Working Directory section of your prompt.** Use relative paths. Do not navigate to any other copy of the project.\n\n### Conventions\n\n- `PROJECT.md`: living current-state doc, refreshed at slice completion when stale.\n- `REQUIREMENTS.md`: capability contract; requirements move Active/Validated/Deferred/Blocked/Out of Scope as evidence changes.\n- `DECISIONS.md` and `KNOWLEDGE.md`: append-only decision/rule registers.\n- `CODEBASE.md`: generated structural cache. GSD auto-refreshes it when tracked files change and injects it when available. Use `/gsd codebase update` only to force refresh.\n- `CONTEXT.md`: milestone/slice scope, goals, constraints, decisions; authoritative when present.\n- Milestones are phases; slices are demoable increments ordered by risk; tasks are single-context units.\n- Checkboxes are toggled by gsd_* tools, never manually.\n- Summaries compress prior work; read them instead of all task details.\n\n### Artifact Templates\n\nTemplates are in `{{templatesDir}}`.\n\n**Always read the relevant template before writing an artifact.** Parsers depend on exact formatting:\n\n- Roadmap slices: `- [ ] **S01: Title** \\`risk:level\\` \\`depends:[]\\``\n- Plan tasks: `- [ ] **T01: Title** \\`est:estimate\\``\n- Summaries use YAML frontmatter\n\n### Commands\n\n- `/gsd` - contextual wizard\n- `/gsd auto` - auto-execute (fresh context per task)\n- `/gsd stop` - stop auto-mode\n- `/gsd status` - progress dashboard overlay\n- `/gsd queue` - queue future milestones (safe while auto-mode is running)\n- `/gsd quick <task>` - quick task with GSD guarantees (atomic commits, state tracking) but no milestone ceremony\n- `/gsd codebase [generate|update|stats]` - manage the `.gsd/CODEBASE.md` cache used for prompt context\n- `{{shortcutDashboard}}` - toggle dashboard overlay\n- `{{shortcutShell}}` - show shell processes\n\n## Execution Heuristics\n\n### Tool rules\n\n**File reading:** Use `read` for file inspection. Never use `cat`, `head`, `tail`, or `sed -n` to view contents. Use `read` with `offset`/`limit` for slicing. `bash` is for searching (`rg`, `grep`, `find`) and commands, not displaying files.\n\n**File editing:** Always `read` before `edit` or overwrite. Before `write`, confirm whether the path exists; if it does, `read` it first and preserve intentional existing content. Use `write` only for new files or complete rewrites.\n\n**Code navigation:** Use `lsp` for definition, type_definition, implementation, references, calls, hover, signature, symbols, rename, code_actions, format, and diagnostics. Do not `grep` symbol definitions or shell out to formatters when `lsp` can do it. After code edits, run `lsp diagnostics`.\n\n**Codebase exploration:** Use `subagent` with `scout` for broad unfamiliar subsystem mapping, `rg` for text search, and `lsp` for structure. Do not read files one-by-one to explore; search first, then read relevant files.\n\n**Documentation lookup:** Use `resolve_library` -> `get_library_docs` for library/framework questions. Start with `tokens=5000`. Never guess API signatures when docs are available.\n\n**External facts:** Use `search-the-web` + `fetch_page`, or `search_and_read`; use `freshness` for recency. Never state current facts from training data without verification.\n\n**Background processes:** Use `bg_shell` `start` + `wait_for_ready` for servers/watchers/daemons. Never use `bash` with `&` or `nohup`; inherited stdout can hang. Never poll with `sleep`; use `wait_for_ready`. For status use `digest`, `highlights` for significant lines, and `output` only when debugging.\n\n**One-shot commands:** Use `async_bash` for builds, tests, and installs. Results are pushed on exit; use `await_job` only to block on a specific job.\n\n**Stale job hygiene:** After editing source to fix a failure, `cancel_job` every in-flight `async_bash` job before rerunning. Changed inputs make in-flight outputs untrusted.\n\n**Secrets:** Use `secure_env_collect`. Never ask the user to edit `.env` files or paste secrets.\n\n**Browser verification:** Verify frontend work against a running app. Discovery: `browser_find`/`browser_snapshot_refs`. Action: refs/selectors -> `browser_batch`. Verification: `browser_assert`. Diagnostics: `browser_diff` -> console/network logs -> full inspection as last resort. Retry only with a new hypothesis.\n\n### Anti-patterns — never do these\n\n- Never use `cat` to read a file you might edit; use `read`.\n- Never `grep` for a function definition when `lsp` go-to-definition is available.\n- Never poll servers with `sleep` loops; use `bg_shell wait_for_ready`.\n- Never background with `bash` + `&`; use `bg_shell start`.\n- Never use `bg_shell output` for status; use `digest`.\n- Never read files one-by-one to understand a subsystem; use `rg` or `scout` first.\n- Never guess library APIs; use `get_library_docs`.\n- Never ask the user to run/check/set something you can do.\n- Never await stale async jobs after editing source; cancel then re-run.\n- Never query `.gsd/gsd.db` directly via `sqlite3`, `better-sqlite3`, or `node -e require('better-sqlite3')`; the engine owns a single-writer WAL connection. Use `gsd_milestone_status`, `gsd_journal_query`, or other `gsd_*` tools.\n\n### Ask vs infer\n\nAsk only when the answer materially affects the result and cannot be derived from repo evidence, docs, runtime behavior, or command output. If multiple interpretations are reasonable, choose the smallest safe reversible action.\n\n### Code structure and abstraction\n\n- Prefer small primitives over monoliths; extract around real seams.\n- Separate orchestration from implementation.\n- Prefer boring standard abstractions over clever custom frameworks.\n- Do not abstract speculatively; keep code local until the seam stabilizes.\n- Preserve local consistency.\n\n### Verification and definition of done\n\nVerify according to task type: bug fix → rerun repro, script fix → rerun command, UI fix → verify in browser, refactor → run tests, env fix → rerun blocked workflow, file ops → confirm filesystem state, docs → verify paths and commands match reality.\n\nFor non-trivial work, verify both the feature and the failure/diagnostic surface. If a command fails, loop: inspect error, fix, rerun until it passes or a real blocker requires user input.\n\nWork is not done when the code compiles. Work is done when the verification passes.\n\n### Agent-First Observability\n\nFor relevant work: add health/status surfaces, persist failure state (last error, phase, timestamp, retry count), verify both happy path and at least one diagnostic signal. Never log secrets. Remove noisy one-off instrumentation before finishing unless it provides durable diagnostic value.\n\n### Root-cause-first debugging\n\nFix root causes, not symptoms. If applying temporary mitigation, label it and preserve the path to the real fix. Never add guards/try-catch to suppress undiagnosed errors.\n\n## Communication\n\n- All plans are for the agent's own execution, not an imaginary team's. No enterprise patterns unless explicitly asked for.\n- Push back on security issues, performance problems, anti-patterns, and unnecessary complexity with concrete reasoning - especially during discussion and planning.\n- Between tool calls, narrate decisions, discoveries, phase transitions, and verification outcomes in one or two complete sentences. Do not narrate every call or the obvious.\n- State uncertainty plainly: \"Not sure this handles X - testing it.\" No performed confidence, no hedging paragraphs.\n- All user-visible narration must be grammatical English. Do not emit compressed planner notes like \"Need inspect X\". If it fits a commit comment or standup note, it is acceptable.\n- When debugging, stay curious. Problems are puzzles. Say what's interesting about the failure before reaching for fixes.\n- After completing a task, give a brief summary and 2-4 numbered next-step options; last option is always \"Other\". Omit the list for strict output formats.\n\nGood narration: \"Three existing handlers follow a middleware pattern - using that instead of a custom wrapper.\"\nGood narration: \"Tests pass. Running slice-level verification.\"\nGood narration: \"I need the task-plan template first, then I'll compare the existing T01 and T02 plans.\"\nBad narration: \"Reading the file now.\" / \"Let me check this.\" / \"I'll look at the tests next.\"\nBad narration: \"Need create plan artifact likely requires template maybe read existing task plans.\"\n","src/resources/extensions/gsd/skills/gsd-headless/SKILL.md":"---\nname: gsd-headless\ndescription: Orchestrate GSD (Get Shit Done) projects programmatically via headless CLI. Use when an agent needs to create milestones from specs, execute software development workflows, monitor task progress, check project status, or control GSD execution (pause/stop/skip/steer). Triggers on requests to \"run gsd\", \"create milestone\", \"execute project\", \"check gsd status\", \"orchestrate development\", \"run headless workflow\", or any programmatic interaction with the GSD project management system. Essential for building orchestrators that coordinate multiple GSD workers.\n---\n\n# GSD Headless Orchestration\n\nRun GSD commands without TUI via `gsd headless`. Spawns an RPC child process, auto-responds to UI prompts, streams progress.\n\n## Command Syntax\n\n```bash\ngsd headless [flags] [command] [args...]\n```\n\n**Flags:**\n- `--timeout N` — overall timeout in ms (default 300000)\n- `--json` — JSONL event stream to stdout\n- `--model ID` — override LLM model\n- `--verbose` — show tool calls in progress output\n- `--supervised` — forward interactive UI requests to orchestrator via stdout/stdin\n- `--response-timeout N` — timeout for orchestrator response in supervised mode (default 30000)\n- `--max-restarts N` — auto-restart on crash with backoff (default 3, 0 to disable)\n- `--answers <path>` — pre-supply answers and secrets from JSON file\n- `--events <types>` — filter JSONL output to specific event types (comma-separated, implies `--json`)\n\n**Exit codes:** 0=complete, 1=error/timeout, 2=blocked\n\n## Core Workflows\n\n### 1. Create + Execute a Milestone (end-to-end)\n\n```bash\ngsd headless new-milestone --context spec.md --auto\n```\n\nReads spec, bootstraps `.gsd/`, creates milestone, then chains into auto-mode executing all phases (discuss → research → plan → execute → summarize → complete).\n\nExtra flags for `new-milestone`: `--context <path>` (use `-` for stdin), `--context-text <text>`, `--auto`.\n\n### 2. Run All Queued Work\n\n```bash\ngsd headless auto\n```\n\nDefault command. Loops through all pending units until milestone complete or blocked.\n\n### 3. Run One Unit\n\n```bash\ngsd headless next\n```\n\nExecute exactly one unit (task/slice/milestone step), then exit. Ideal for step-by-step orchestration with external decision logic between steps.\n\n### 4. Instant State Snapshot (no LLM)\n\n```bash\ngsd headless query\n```\n\nReturns a single JSON object with the full project snapshot — no LLM session, instant (~50ms). **This is the recommended way for orchestrators to inspect state.**\n\n```json\n{\n  \"state\": { \"phase\": \"executing\", \"activeMilestone\": {...}, \"activeSlice\": {...}, \"progress\": {...}, \"registry\": [...] },\n  \"next\":  { \"action\": \"dispatch\", \"unitType\": \"execute-task\", \"unitId\": \"M001/S01/T01\" },\n  \"cost\":  { \"workers\": [{ \"milestoneId\": \"M001\", \"cost\": 1.50, ... }], \"total\": 1.50 }\n}\n```\n\n```bash\n# What phase is the project in?\ngsd headless query | jq '.state.phase'\n\n# What would auto-mode do next?\ngsd headless query | jq '.next'\n\n# Total spend across parallel workers\ngsd headless query | jq '.cost.total'\n```\n\n### 5. Dispatch Specific Phase\n\n```bash\ngsd headless dispatch research|plan|execute|complete|reassess|uat|replan\n```\n\nForce-route to a specific phase, bypassing normal state-machine routing.\n\n## Orchestrator Patterns\n\n### Poll-and-React Loop\n\n```bash\n# Instant state check — no LLM cost\nPHASE=$(gsd headless query | jq -r '.state.phase')\nNEXT_ACTION=$(gsd headless query | jq -r '.next.action')\n\ncase \"$PHASE\" in\n  complete) echo \"Done\" ;;\n  blocked)  echo \"Needs intervention\" ;;\n  *)        [ \"$NEXT_ACTION\" = \"dispatch\" ] && gsd headless next ;;\nesac\n```\n\n### Step-by-Step with Monitoring\n\n```bash\nwhile true; do\n  gsd headless next\n  EXIT=$?\n  [ $EXIT -ne 0 ] && break\n  # Instant progress check between steps\n  gsd headless query | jq '{phase: .state.phase, progress: .state.progress}'\ndone\n```\n\n### Multi-Session Orchestration\n\nGSD tracks concurrent workers via file-based IPC in `.gsd/parallel/`. See [references/multi-session.md](references/multi-session.md) for the full architecture.\n\n**Quick overview:**\n\nEach worker spawns with `GSD_MILESTONE_LOCK=M00X` + its own git worktree. Workers write heartbeats to `.gsd/parallel/<milestoneId>.status.json`. The orchestrator enumerates all status files to get a dashboard of all workers, and sends commands via signal files.\n\n```bash\n# Spawn a worker for milestone M001 in its worktree\nGSD_MILESTONE_LOCK=M001 GSD_PARALLEL_WORKER=1 \\\n  gsd headless --json auto \\\n  --cwd .gsd/worktrees/M001 2>worker-M001.log &\n\n# Monitor all workers: read .gsd/parallel/*.status.json\nfor f in .gsd/parallel/*.status.json; do\n  jq '{mid: .milestoneId, state: .state, unit: .currentUnit.id, cost: .cost}' \"$f\"\ndone\n\n# Send pause signal to M001\necho '{\"signal\":\"pause\",\"sentAt\":'$(date +%s000)',\"from\":\"coordinator\"}' \\\n  > .gsd/parallel/M001.signal.json\n```\n\n**Status file fields:** `milestoneId`, `pid`, `state` (running/paused/stopped/error), `currentUnit`, `completedUnits`, `cost`, `lastHeartbeat`, `startedAt`, `worktreePath`.\n\n**Signal commands:** `pause`, `resume`, `stop`, `rebase`.\n\n**Liveness detection:** PID alive check (`kill -0 $pid`) + heartbeat freshness (30s timeout). Stale sessions are auto-cleaned.\n\n**For multiple projects:** each project has its own `.gsd/` directory. The orchestrator must track `(projectPath, milestoneId)` tuples externally.\n\n### JSONL Event Stream\n\nUse `--json` to get real-time events on stdout for downstream processing:\n\n```bash\ngsd headless --json auto 2>/dev/null | while read -r line; do\n  TYPE=$(echo \"$line\" | jq -r '.type')\n  case \"$TYPE\" in\n    tool_execution_start) echo \"Tool: $(echo \"$line\" | jq -r '.toolName')\" ;;\n    extension_ui_request) echo \"GSD: $(echo \"$line\" | jq -r '.message // .title // empty')\" ;;\n    agent_end) echo \"Session ended\" ;;\n  esac\ndone\n```\n\nEvent types: `agent_start`, `agent_end`, `tool_execution_start`, `tool_execution_end`, `extension_ui_request`, `message_update`, `error`.\n\n### Filtered Event Stream\n\nUse `--events` to receive only specific event types — reduces noise for orchestrators:\n\n```bash\n# Only phase-relevant events\ngsd headless --events agent_end,extension_ui_request auto 2>/dev/null\n\n# Only tool execution events\ngsd headless --events tool_execution_start,tool_execution_end auto\n```\n\nThe filter applies only to stdout output. Internal processing (completion detection, supervised mode, answer injection) is unaffected — all events are still processed internally.\n\nAvailable event types: `agent_start`, `agent_end`, `tool_execution_start`, `tool_execution_end`, `tool_execution_update`, `extension_ui_request`, `message_start`, `message_end`, `message_update`, `turn_start`, `turn_end`.\n\n## Answer Injection\n\nPre-supply answers and secrets for headless runs via `--answers`:\n\n```bash\ngsd headless --answers answers.json auto\n```\n\nAnswer file schema:\n```json\n{\n  \"questions\": { \"question_id\": \"selected_option\" },\n  \"secrets\": { \"API_KEY\": \"sk-...\" },\n  \"defaults\": { \"strategy\": \"first_option\" }\n}\n```\n\n- **questions** — question ID → answer (string or string[])\n- **secrets** — env var → value, injected into child process env\n- **defaults.strategy** — `\"first_option\"` (default) or `\"cancel\"` for unmatched\n\nSee [references/answer-injection.md](references/answer-injection.md) for full details.\n\n## GSD Project Structure\n\nAll state lives in `.gsd/` as markdown files (version-controllable):\n\n```\n.gsd/\n  milestones/M001/\n    M001-CONTEXT.md      # Requirements, scope, decisions\n    M001-ROADMAP.md      # Slices with tasks, dependencies, checkboxes\n    M001-SUMMARY.md      # Completion summary\n    slices/S01/\n      S01-PLAN.md        # Task list\n      S01-SUMMARY.md     # Slice summary with frontmatter\n      tasks/T01-PLAN.md  # Individual task spec\n```\n\nState is derived from files on disk — checkboxes in ROADMAP.md are the source of truth for completion.\n\n## All Headless Commands\n\nQuick reference — see [references/commands.md](references/commands.md) for the complete list.\n\n| Command | Purpose |\n|---------|---------|\n| `auto` | Run all queued units (default) |\n| `next` | Run one unit |\n| `query` | Instant JSON snapshot — state, next dispatch, costs (no LLM) |\n| `new-milestone` | Create milestone from spec |\n| `queue` | Queue/reorder milestones |\n| `history` | View execution history |\n| `stop` / `pause` | Control auto-mode |\n| `dispatch <phase>` | Force specific phase |\n| `skip` / `undo` | Unit control |\n| `doctor` | Health check + auto-fix |\n| `steer <desc>` | Hard-steer plan mid-execution |\n","src/resources/extensions/gsd/skills/gsd-headless/references/answer-injection.md":"# Answer Injection\n\nPre-supply answers to eliminate interactive prompts during headless execution.\n\n## CLI Usage\n\n```bash\ngsd headless --answers answers.json auto\ngsd headless --answers answers.json new-milestone --context spec.md --auto\n```\n\nThe `--answers` flag takes a path to a JSON file containing pre-supplied answers and secrets.\n\n## Answer File Schema\n\n```json\n{\n  \"questions\": {\n    \"question_id\": \"selected_option_label\",\n    \"multi_select_question\": [\"option_a\", \"option_b\"]\n  },\n  \"secrets\": {\n    \"API_KEY\": \"sk-...\",\n    \"DATABASE_URL\": \"postgres://...\"\n  },\n  \"defaults\": {\n    \"strategy\": \"first_option\"\n  }\n}\n```\n\n### Fields\n\n- **questions**: Map question ID → answer. String for single-select, string[] for multi-select.\n- **secrets**: Map env var name → value. Injected as environment variables into the RPC child process. The child's `checkExistingEnvKeys()` detects them in `process.env` and marks them as \"already set\" — no interactive prompt needed.\n- **defaults.strategy**: Fallback for unmatched questions.\n  - `\"first_option\"` — auto-select first available option (default)\n  - `\"cancel\"` — cancel the request\n\n## Secrets Mechanism\n\nSecrets are injected via the `RpcClient` `env` option, which merges them into the child process's `process.env`. This means:\n\n1. The headless orchestrator reads the answer file\n2. Secret values are passed as `env` to `RpcClient`\n3. The child process spawns with these env vars set\n4. When `secure_env_collect` runs, `checkExistingEnvKeys()` finds the keys already in `process.env`\n5. The tool skips the interactive prompt and reports the keys as \"already configured\"\n\nSecrets are never logged or included in event streams.\n\n## How It Works\n\nTwo-phase correlation:\n1. **Observe** `tool_execution_start` events for `ask_user_questions` — extracts question metadata (ID, options, allowMultiple)\n2. **Match** subsequent `extension_ui_request` events to metadata, respond with pre-supplied answer\n\nHandles out-of-order events (extension_ui_request can arrive before tool_execution_start in RPC mode) via deferred processing queue with 500ms timeout.\n\n## Coexistence with --supervised\n\nBoth `--answers` and `--supervised` can be active simultaneously. Priority order:\n1. Answer injector tries first\n2. If no answer found, supervised mode takes over\n3. If no orchestrator response, auto-responder kicks in after timeout\n\n## Without Answer Injection\n\nHeadless mode has built-in auto-responders:\n- **select** → picks first option\n- **confirm** → auto-confirms\n- **input** → empty string\n- **editor** → returns prefill or empty\n\nAnswer injection overrides these defaults with specific answers when precision matters.\n\n## Diagnostics\n\nThe injector tracks stats printed in the summary:\n- `questionsAnswered` / `questionsDefaulted`\n- `secretsProvided`\n\nUnused question IDs and secret keys are warned about at the end.\n","src/resources/extensions/gsd/skills/gsd-headless/references/commands.md":"# GSD Commands Reference\n\nAll commands can be run via `gsd headless [command]`.\n\n## Workflow Commands\n\n| Command | Description |\n|---------|-------------|\n| `auto` | Autonomous mode — loop until milestone complete (default) |\n| `next` | Step mode — execute one unit, then exit |\n| `stop` | Stop auto-mode gracefully |\n| `pause` | Pause auto-mode (preserves state, resumable) |\n| `new-milestone` | Create milestone from specification (requires `--context`) |\n| `dispatch <phase>` | Force-dispatch: research, plan, execute, complete, reassess, uat, replan |\n| `discuss` | Start guided milestone/slice discussion |\n\n## State Inspection\n\n| Command | Description |\n|---------|-------------|\n| `query` | **Instant JSON snapshot** — state, next dispatch, parallel costs. No LLM, ~50ms. Recommended for orchestrators. |\n| `status` | Progress dashboard (TUI overlay — useful interactively, not for parsing) |\n| `visualize` | Workflow visualizer (deps, metrics, timeline) |\n| `history` | Execution history (supports --cost, --phase, --model, limit) |\n\n## Unit Control\n\n| Command | Description |\n|---------|-------------|\n| `skip` | Prevent a unit from auto-mode dispatch |\n| `undo` | Revert last completed unit (--force flag) |\n| `steer <desc>` | Hard-steer plan documents during execution |\n| `queue` | Queue and reorder future milestones |\n| `capture` | Fire-and-forget thought capture |\n| `triage` | Manually trigger triage of pending captures |\n\n## Configuration & Health\n\n| Command | Description |\n|---------|-------------|\n| `prefs` | Manage preferences (global/project/status/wizard/setup) |\n| `config` | Set API keys for external tools |\n| `doctor` | Runtime health checks with auto-fix |\n| `hooks` | Show configured post-unit and pre-dispatch hooks |\n| `knowledge <rule\\|pattern\\|lesson>` | Add persistent project knowledge |\n| `cleanup` | Remove merged branches or snapshots |\n| `export` | Export results (--json, --markdown) |\n| `migrate` | Migrate v1 .planning directory to DB-backed .gsd with backup and audit |\n| `remote` | Control remote auto-mode (slack, discord, status, disconnect) |\n| `inspect` | Show SQLite DB diagnostics (schema, row counts) |\n| `forensics` | Post-mortem investigation of auto-mode failures |\n\n## Phases\n\nGSD workflows progress through these phases:\n`pre-planning` → `needs-discussion` → `discussing` → `researching` → `planning` → `executing` → `verifying` → `summarizing` → `advancing` → `validating-milestone` → `completing-milestone` → `complete`\n\nSpecial phases: `paused`, `blocked`, `replanning-slice`\n\n## Hierarchy\n\n- **Milestone**: Shippable version (4-10 slices, 1-4 weeks)\n- **Slice**: One demoable vertical capability (1-7 tasks, 1-3 days)\n- **Task**: One context-window-sized unit of work (one session)\n","src/resources/extensions/gsd/skills/gsd-headless/references/multi-session.md":"# Multi-Session Orchestration\n\nHow to run and monitor multiple concurrent GSD sessions.\n\n## Architecture\n\nGSD uses **file-based IPC** — no sockets or ports. All coordination happens through JSON files in `.gsd/parallel/`.\n\n```\n.gsd/parallel/\n├── M001.status.json    # Worker heartbeat + state\n├── M001.signal.json    # Coordinator → worker commands (ephemeral)\n├── M002.status.json\n├── M003.status.json\n└── ...\n```\n\n## Worker Isolation\n\nEach worker gets:\n1. **`GSD_MILESTONE_LOCK=M00X`** — state derivation only sees this milestone\n2. **`GSD_PARALLEL_WORKER=1`** — prevents nested parallel spawns\n3. **Own git worktree** at `.gsd/worktrees/M00X/` — branch `milestone/M00X`\n\nWorkers cannot interfere with each other. Each has its own filesystem and git branch.\n\n## Status File Schema\n\nWritten atomically (`.tmp` + rename) by each worker at `.gsd/parallel/<milestoneId>.status.json`:\n\n```json\n{\n  \"milestoneId\": \"M001\",\n  \"pid\": 12345,\n  \"state\": \"running\",\n  \"currentUnit\": {\n    \"type\": \"task\",\n    \"id\": \"T03\",\n    \"startedAt\": 1710000000000\n  },\n  \"completedUnits\": 7,\n  \"cost\": 1.23,\n  \"lastHeartbeat\": 1710000015000,\n  \"startedAt\": 1710000000000,\n  \"worktreePath\": \".gsd/worktrees/M001\"\n}\n```\n\n**States:** `running`, `paused`, `stopped`, `error`\n\n## Signal Files\n\nCoordinator writes to `.gsd/parallel/<milestoneId>.signal.json`. Worker consumes and deletes on next dispatch cycle.\n\n```json\n{\n  \"signal\": \"pause\",\n  \"sentAt\": 1710000020000,\n  \"from\": \"coordinator\"\n}\n```\n\n**Signals:** `pause`, `resume`, `stop`, `rebase`\n\n## Spawning Workers\n\n```bash\n# Spawn worker in its worktree\nGSD_MILESTONE_LOCK=M001 \\\nGSD_PARALLEL_WORKER=1 \\\n  gsd headless --json auto 2>logs/M001.log &\nWORKER_PID=$!\n```\n\nWorkers emit JSONL events on stdout when `--json` is set.\n\n## Monitoring All Workers\n\n```bash\n# Dashboard: enumerate all status files\nfor f in .gsd/parallel/*.status.json; do\n  [ -f \"$f\" ] || continue\n  jq -r '[.milestoneId, .state, (.currentUnit.id // \"idle\"), \"\\(.cost | tostring)$\"] | join(\"\\t\")' \"$f\"\ndone\n\n# Liveness check\nfor f in .gsd/parallel/*.status.json; do\n  PID=$(jq -r '.pid' \"$f\")\n  MID=$(jq -r '.milestoneId' \"$f\")\n  if kill -0 \"$PID\" 2>/dev/null; then\n    echo \"$MID: alive (pid=$PID)\"\n  else\n    echo \"$MID: DEAD (pid=$PID) — cleanup needed\"\n    rm \"$f\"\n  fi\ndone\n```\n\n## Sending Commands\n\n```bash\n# Pause a worker\nsend_signal() {\n  local MID=$1 SIGNAL=$2\n  echo \"{\\\"signal\\\":\\\"$SIGNAL\\\",\\\"sentAt\\\":$(date +%s000),\\\"from\\\":\\\"coordinator\\\"}\" \\\n    > \".gsd/parallel/${MID}.signal.json\"\n}\n\nsend_signal M001 pause\nsend_signal M002 stop\nsend_signal M003 resume\n```\n\n## Budget Enforcement\n\nUse `gsd headless query` for instant aggregate cost:\n```bash\nTOTAL=$(gsd headless query | jq -r '.cost.total')\nCEILING=50.00\nif (( $(echo \"$TOTAL > $CEILING\" | bc -l) )); then\n  echo \"Budget exceeded ($TOTAL > $CEILING) — stopping all\"\n  for f in .gsd/parallel/*.status.json; do\n    MID=$(jq -r '.milestoneId' \"$f\")\n    send_signal \"$MID\" stop\n  done\nfi\n```\n\n## Stale Session Cleanup\n\nA session is stale when:\n- PID is dead (`kill -0 $pid` fails), OR\n- `lastHeartbeat` is older than 30 seconds\n\n```bash\nNOW=$(date +%s000)\nSTALE_THRESHOLD=30000\nfor f in .gsd/parallel/*.status.json; do\n  PID=$(jq -r '.pid' \"$f\")\n  HB=$(jq -r '.lastHeartbeat' \"$f\")\n  AGE=$((NOW - HB))\n  if ! kill -0 \"$PID\" 2>/dev/null || [ \"$AGE\" -gt \"$STALE_THRESHOLD\" ]; then\n    echo \"Stale: $(jq -r '.milestoneId' \"$f\") — removing\"\n    rm \"$f\"\n  fi\ndone\n```\n\n## Multi-Project Orchestration\n\nWithin one project, milestones are tracked automatically in `.gsd/parallel/`. For orchestrating across **multiple projects**, maintain an external registry:\n\n```json\n{\n  \"sessions\": [\n    { \"project\": \"/path/to/project-a\", \"milestoneId\": \"M001\" },\n    { \"project\": \"/path/to/project-b\", \"milestoneId\": \"M001\" },\n    { \"project\": \"/path/to/project-b\", \"milestoneId\": \"M002\" }\n  ]\n}\n```\n\nThen poll each project's `.gsd/parallel/` directory. GSD has no cross-project awareness — the orchestrator must bridge this gap.\n\n## Built-in Parallel Commands\n\nInside an interactive GSD session, these commands manage the parallel orchestrator:\n\n| Command | Description |\n|---------|-------------|\n| `/gsd parallel start` | Analyze eligibility, spawn workers |\n| `/gsd parallel status` | Show all workers, costs, progress |\n| `/gsd parallel stop [MID]` | Stop one or all workers |\n| `/gsd parallel pause [MID]` | Pause without killing |\n| `/gsd parallel resume [MID]` | Resume paused worker |\n| `/gsd parallel merge [MID]` | Merge completed milestone branch |\n","src/resources/extensions/gsd/templates/milestone-summary.md":"---\nid: {{milestoneId}}\nprovides:\n  - {{whatThisMilestoneProvides}}\nkey_decisions:\n  - {{decision}}\npatterns_established:\n  - {{pattern}}\nobservability_surfaces:\n  - {{status endpoint, structured log, persisted failure state, diagnostic command, or none}}\nrequirement_outcomes:\n  - id: {{requirementId}}\n    from_status: {{active|blocked|deferred}}\n    to_status: {{validated|deferred|blocked|out_of_scope}}\n    proof: {{whatEvidenceSupportsThisTransition}}\nduration: {{duration}}\nverification_result: passed\ncompleted_at: {{date}}\n---\n\n# {{milestoneId}}: {{milestoneTitle}}\n\n<!-- One-liner must say what the milestone actually delivered, not just that it completed.\n     Good: \"State machine integrity with completing-milestone gating, doctor audits, and observability validation\"\n     Bad: \"Milestone 2 completed\" -->\n\n**{{oneLiner}}**\n\n## What Happened\n\n<!-- Cross-slice narrative: compress all slice summaries into a coherent story.\n     Focus on what was built, how the slices connected, and what the milestone\n     achieved as a whole — not a task-by-task replay. -->\n\n{{crossSliceNarrative}}\n\n## Cross-Slice Verification\n\n<!-- How were the milestone's success criteria verified?\n     Reference specific tests, commands, browser checks, or observable behaviors.\n     Each success criterion from the roadmap should have a corresponding verification entry. -->\n\n{{howSuccessCriteriaWereVerified}}\n\n## Requirement Changes\n\n<!-- Transitions with evidence. Each requirement that changed status during this milestone\n     should be listed with the proof that supports the transition. -->\n\n- {{requirementId}}: {{fromStatus}} → {{toStatus}} — {{evidence}}\n\n## Decision Re-evaluation\n\n<!-- Review decisions from this milestone. OMIT if no decisions need re-evaluation. -->\n\n| Decision | Original Rationale | Still Valid? | Action |\n|----------|-------------------|-------------|--------|\n| {{decisionId}} | {{originalRationale}} | {{yes/no/partially}} | {{keep/revise/supersede}} |\n\n## Forward Intelligence\n\n<!-- Write what you wish you'd known at the start of this milestone.\n     This section is read by the next milestone's planning and research steps.\n     Be specific and concrete — this is the most valuable context you can transfer. -->\n\n### What the next milestone should know\n- {{insightThatWouldHelpDownstreamWork}}\n\n### What's fragile\n- {{fragileAreaOrThinImplementation}} — {{whyItMatters}}\n\n### Authoritative diagnostics\n- {{whereAFutureAgentShouldLookFirst}} — {{whyThisSignalIsTrustworthy}}\n\n### What assumptions changed\n- {{originalAssumption}} — {{whatActuallyHappened}}\n\n## Files Created/Modified\n\n- `{{filePath}}` — {{description}}\n- `{{filePath}}` — {{description}}\n","src/resources/extensions/gsd/templates/slice-summary.md":"---\nid: {{sliceId}}\nparent: {{milestoneId}}\nmilestone: {{milestoneId}}\nprovides:\n  - {{whatThisSliceProvides}}\nrequires:\n  - slice: {{depSliceId}}\n    provides: {{whatWasConsumed}}\naffects:\n  - {{downstreamSliceId}}\nkey_files:\n  - {{filePath}}\nkey_decisions:\n  - {{decision}}\npatterns_established:\n  - {{pattern}}\nobservability_surfaces:\n  - {{status endpoint, structured log, persisted failure state, diagnostic command, or none}}\ndrill_down_paths:\n  - {{pathToTaskSummary}}\nduration: {{duration}}\nverification_result: passed\ncompleted_at: {{date}}\n---\n\n# {{sliceId}}: {{sliceTitle}}\n\n<!-- One-liner must say what actually shipped, not just that work completed.\n     Good: \"Structured job status endpoint with persisted failure diagnostics\"\n     Bad: \"Status feature implemented\" -->\n\n**{{oneLiner}}**\n\n## What Happened\n\n{{narrative — compress task summaries into a coherent story}}\n\n## Verification\n\n{{whatWasVerifiedAcrossAllTasks — tests, builds, manual checks}}\n\n<!-- If the project has no REQUIREMENTS.md, omit all four requirement sections below entirely — do not fill them with \"none\". These sections only apply when requirements are being actively tracked. -->\n## Requirements Advanced\n\n- {{requirementId}} — {{howThisSliceAdvancedIt}}\n\n## Requirements Validated\n\n- {{requirementId}} — {{whatProofNowMakesItValidated}}\n\n## New Requirements Surfaced\n\n- {{newRequirementOr_none}}\n\n## Requirements Invalidated or Re-scoped\n\n- {{requirementIdOr_none}} — {{what changed}}\n\n## Operational Readiness\n\n<!-- Q8: How will ops know it's healthy/broken? OMIT ENTIRELY for simple slices with no runtime concerns. -->\n\n- **Health signal**: {{howToConfirmHealthy — health endpoint, heartbeat log, metric, or N/A}}\n- **Failure signal**: {{howToDetectBroken — error rate spike, alert, log pattern, or N/A}}\n- **Recovery**: {{selfRecoverOrRestart — auto-reconnect, circuit breaker, manual restart, or N/A}}\n- **Monitoring gaps**: {{silentFailureModes — background jobs, cache eviction, memory pressure, or none}}\n\n## Deviations\n\n<!-- Deviations are unplanned changes to the written plan, not ordinary debugging inside the plan's intended scope. -->\n\n{{deviationsFromPlan_OR_none}}\n\n## Known Limitations\n\n<!-- Known limitations are real gaps, rough edges, or deferred constraints that still exist after this slice shipped. -->\n\n{{whatDoesntWorkYet_OR_whatWasDeferredToLaterSlices}}\n\n## Follow-ups\n\n<!-- Follow-ups are concrete next actions discovered during execution, not a restatement of known limitations. -->\n\n{{workDeferredOrDiscoveredDuringExecution_OR_none}}\n\n## Files Created/Modified\n\n- `{{filePath}}` — {{description}}\n- `{{filePath}}` — {{description}}\n\n## Forward Intelligence\n\n<!-- Write what you wish you'd known at the start of this slice.\n     This section is read by the next slice's planning and research steps.\n     Be specific and concrete — this is the most valuable context you can transfer. -->\n\n### What the next slice should know\n- {{insightThatWouldHelpDownstreamWork}}\n\n### What's fragile\n- {{fragileAreaOrThinImplementation}} — {{whyItMatters}}\n\n### Authoritative diagnostics\n- {{whereAFutureAgentShouldLookFirst}} — {{whyThisSignalIsTrustworthy}}\n\n### What assumptions changed\n- {{originalAssumption}} — {{whatActuallyHappened}}\n","src/resources/extensions/gsd/templates/task-summary.md":"---\nid: {{taskId}}\nparent: {{sliceId}}\nmilestone: {{milestoneId}}\nprovides:\n  - {{whatThisTaskProvides}}\nkey_files:\n  - {{filePath}}\nkey_decisions:\n  - {{decision}}\npatterns_established:\n  - {{pattern}}\nobservability_surfaces:\n  - {{status endpoint, structured log, persisted failure state, diagnostic command, or none}}\nduration: {{duration}}\nverification_result: passed\ncompleted_at: {{date}}\n# Set blocker_discovered: true only if execution revealed the remaining slice plan\n# is fundamentally invalid (wrong API, missing capability, architectural mismatch).\n# Do NOT set true for ordinary bugs, minor deviations, or fixable issues.\nblocker_discovered: false\n---\n\n# {{taskId}}: {{taskTitle}}\n\n<!-- One-liner must say what actually shipped, not just that work completed.\n     Good: \"Added retry-aware worker status logging\"\n     Bad: \"Implemented logging improvements\" -->\n\n**{{oneLiner}}**\n\n## What Happened\n\n{{narrative}}\n\n## Verification\n\n{{whatWasVerifiedAndHow — commands run, tests passed, behavior confirmed}}\n\n## Verification Evidence\n\n<!-- Populated from verification gate output. If the gate ran, fill in the table below.\n     If no gate ran (e.g., no verification commands discovered), note that. -->\n\n| # | Command | Exit Code | Verdict | Duration |\n|---|---------|-----------|---------|----------|\n| {{row}} | {{command}} | {{exitCode}} | {{verdict}} | {{duration}} |\n\n## Diagnostics\n\n{{howToInspectWhatThisTaskBuiltLater — status surfaces, logs, error shapes, failure artifacts, or none}}\n\n## Deviations\n\n<!-- Deviations are unplanned changes to the written task plan, not ordinary debugging during implementation. -->\n\n{{deviationsFromPlan_OR_none}}\n\n## Known Issues\n\n{{issuesDiscoveredButNotFixed_OR_none}}\n\n## Files Created/Modified\n\n- `{{filePath}}` — {{description}}\n- `{{filePath}}` — {{description}}\n","src/resources/skills/accessibility/SKILL.md":"---\nname: accessibility\ndescription: Audit and improve web accessibility following WCAG 2.1 guidelines. Use when asked to \"improve accessibility\", \"a11y audit\", \"WCAG compliance\", \"screen reader support\", \"keyboard navigation\", or \"make accessible\".\nlicense: MIT\nmetadata:\n  author: web-quality-skills\n  version: \"1.0\"\n---\n\n# Accessibility (a11y)\n\nComprehensive accessibility guidelines based on WCAG 2.1 and Lighthouse accessibility audits. Goal: make content usable by everyone, including people with disabilities.\n\n## WCAG Principles: POUR\n\n| Principle | Description |\n|-----------|-------------|\n| **P**erceivable | Content can be perceived through different senses |\n| **O**perable | Interface can be operated by all users |\n| **U**nderstandable | Content and interface are understandable |\n| **R**obust | Content works with assistive technologies |\n\n## Conformance levels\n\n| Level | Requirement | Target |\n|-------|-------------|--------|\n| **A** | Minimum accessibility | Must pass |\n| **AA** | Standard compliance | Should pass (legal requirement in many jurisdictions) |\n| **AAA** | Enhanced accessibility | Nice to have |\n\n---\n\n## Perceivable\n\n### Text alternatives (1.1)\n\n**Images require alt text:**\n```html\n<!-- ❌ Missing alt -->\n<img src=\"chart.png\">\n\n<!-- ✅ Descriptive alt -->\n<img src=\"chart.png\" alt=\"Bar chart showing 40% increase in Q3 sales\">\n\n<!-- ✅ Decorative image (empty alt) -->\n<img src=\"decorative-border.png\" alt=\"\" role=\"presentation\">\n\n<!-- ✅ Complex image with longer description -->\n<figure>\n  <img src=\"infographic.png\" alt=\"2024 market trends infographic\" \n       aria-describedby=\"infographic-desc\">\n  <figcaption id=\"infographic-desc\">\n    <!-- Detailed description -->\n  </figcaption>\n</figure>\n```\n\n**Icon buttons need accessible names:**\n```html\n<!-- ❌ No accessible name -->\n<button><svg><!-- menu icon --></svg></button>\n\n<!-- ✅ Using aria-label -->\n<button aria-label=\"Open menu\">\n  <svg aria-hidden=\"true\"><!-- menu icon --></svg>\n</button>\n\n<!-- ✅ Using visually hidden text -->\n<button>\n  <svg aria-hidden=\"true\"><!-- menu icon --></svg>\n  <span class=\"visually-hidden\">Open menu</span>\n</button>\n```\n\n**Visually hidden class:**\n```css\n.visually-hidden {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: -1px;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  white-space: nowrap;\n  border: 0;\n}\n```\n\n### Color contrast (1.4.3, 1.4.6)\n\n| Text Size | AA minimum | AAA enhanced |\n|-----------|------------|--------------|\n| Normal text (< 18px / < 14px bold) | 4.5:1 | 7:1 |\n| Large text (≥ 18px / ≥ 14px bold) | 3:1 | 4.5:1 |\n| UI components & graphics | 3:1 | 3:1 |\n\n```css\n/* ❌ Low contrast (2.5:1) */\n.low-contrast {\n  color: #999;\n  background: #fff;\n}\n\n/* ✅ Sufficient contrast (7:1) */\n.high-contrast {\n  color: #333;\n  background: #fff;\n}\n\n/* ✅ Focus states need contrast too */\n:focus-visible {\n  outline: 2px solid #005fcc;\n  outline-offset: 2px;\n}\n```\n\n**Don't rely on color alone:**\n```html\n<!-- ❌ Only color indicates error -->\n<input class=\"error-border\">\n<style>.error-border { border-color: red; }</style>\n\n<!-- ✅ Color + icon + text -->\n<div class=\"field-error\">\n  <input aria-invalid=\"true\" aria-describedby=\"email-error\">\n  <span id=\"email-error\" class=\"error-message\">\n    <svg aria-hidden=\"true\"><!-- error icon --></svg>\n    Please enter a valid email address\n  </span>\n</div>\n```\n\n### Media alternatives (1.2)\n\n```html\n<!-- Video with captions -->\n<video controls>\n  <source src=\"video.mp4\" type=\"video/mp4\">\n  <track kind=\"captions\" src=\"captions.vtt\" srclang=\"en\" label=\"English\" default>\n  <track kind=\"descriptions\" src=\"descriptions.vtt\" srclang=\"en\" label=\"Descriptions\">\n</video>\n\n<!-- Audio with transcript -->\n<audio controls>\n  <source src=\"podcast.mp3\" type=\"audio/mp3\">\n</audio>\n<details>\n  <summary>Transcript</summary>\n  <p>Full transcript text...</p>\n</details>\n```\n\n---\n\n## Operable\n\n### Keyboard accessible (2.1)\n\n**All functionality must be keyboard accessible:**\n```javascript\n// ❌ Only handles click\nelement.addEventListener('click', handleAction);\n\n// ✅ Handles both click and keyboard\nelement.addEventListener('click', handleAction);\nelement.addEventListener('keydown', (e) => {\n  if (e.key === 'Enter' || e.key === ' ') {\n    e.preventDefault();\n    handleAction();\n  }\n});\n```\n\n**No keyboard traps:**\n```javascript\n// Modal focus management\nfunction openModal(modal) {\n  const focusableElements = modal.querySelectorAll(\n    'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n  );\n  const firstElement = focusableElements[0];\n  const lastElement = focusableElements[focusableElements.length - 1];\n  \n  // Trap focus within modal\n  modal.addEventListener('keydown', (e) => {\n    if (e.key === 'Tab') {\n      if (e.shiftKey && document.activeElement === firstElement) {\n        e.preventDefault();\n        lastElement.focus();\n      } else if (!e.shiftKey && document.activeElement === lastElement) {\n        e.preventDefault();\n        firstElement.focus();\n      }\n    }\n    if (e.key === 'Escape') {\n      closeModal();\n    }\n  });\n  \n  firstElement.focus();\n}\n```\n\n### Focus visible (2.4.7)\n\n```css\n/* ❌ Never remove focus outlines */\n*:focus { outline: none; }\n\n/* ✅ Use :focus-visible for keyboard-only focus */\n:focus {\n  outline: none;\n}\n\n:focus-visible {\n  outline: 2px solid #005fcc;\n  outline-offset: 2px;\n}\n\n/* ✅ Or custom focus styles */\nbutton:focus-visible {\n  box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.5);\n}\n```\n\n### Skip links (2.4.1)\n\n```html\n<body>\n  <a href=\"#main-content\" class=\"skip-link\">Skip to main content</a>\n  <header><!-- navigation --></header>\n  <main id=\"main-content\" tabindex=\"-1\">\n    <!-- main content -->\n  </main>\n</body>\n```\n\n```css\n.skip-link {\n  position: absolute;\n  top: -40px;\n  left: 0;\n  background: #000;\n  color: #fff;\n  padding: 8px 16px;\n  z-index: 100;\n}\n\n.skip-link:focus {\n  top: 0;\n}\n```\n\n### Timing (2.2)\n\n```javascript\n// Allow users to extend time limits\nfunction showSessionWarning() {\n  const modal = createModal({\n    title: 'Session Expiring',\n    content: 'Your session will expire in 2 minutes.',\n    actions: [\n      { label: 'Extend session', action: extendSession },\n      { label: 'Log out', action: logout }\n    ],\n    timeout: 120000 // 2 minutes to respond\n  });\n}\n```\n\n### Motion (2.3)\n\n```css\n/* Respect reduced motion preference */\n@media (prefers-reduced-motion: reduce) {\n  *,\n  *::before,\n  *::after {\n    animation-duration: 0.01ms !important;\n    animation-iteration-count: 1 !important;\n    transition-duration: 0.01ms !important;\n    scroll-behavior: auto !important;\n  }\n}\n```\n\n---\n\n## Understandable\n\n### Page language (3.1.1)\n\n```html\n<!-- ❌ No language specified -->\n<html>\n\n<!-- ✅ Language specified -->\n<html lang=\"en\">\n\n<!-- ✅ Language changes within page -->\n<p>The French word for hello is <span lang=\"fr\">bonjour</span>.</p>\n```\n\n### Consistent navigation (3.2.3)\n\n```html\n<!-- Navigation should be consistent across pages -->\n<nav aria-label=\"Main\">\n  <ul>\n    <li><a href=\"/\" aria-current=\"page\">Home</a></li>\n    <li><a href=\"/products\">Products</a></li>\n    <li><a href=\"/about\">About</a></li>\n  </ul>\n</nav>\n```\n\n### Form labels (3.3.2)\n\n```html\n<!-- ❌ No label association -->\n<input type=\"email\" placeholder=\"Email\">\n\n<!-- ✅ Explicit label -->\n<label for=\"email\">Email address</label>\n<input type=\"email\" id=\"email\" name=\"email\" \n       autocomplete=\"email\" required>\n\n<!-- ✅ Implicit label -->\n<label>\n  Email address\n  <input type=\"email\" name=\"email\" autocomplete=\"email\" required>\n</label>\n\n<!-- ✅ With instructions -->\n<label for=\"password\">Password</label>\n<input type=\"password\" id=\"password\" \n       aria-describedby=\"password-requirements\">\n<p id=\"password-requirements\">\n  Must be at least 8 characters with one number.\n</p>\n```\n\n### Error handling (3.3.1, 3.3.3)\n\n```html\n<!-- Announce errors to screen readers -->\n<form novalidate>\n  <div class=\"field\" aria-live=\"polite\">\n    <label for=\"email\">Email</label>\n    <input type=\"email\" id=\"email\" \n           aria-invalid=\"true\"\n           aria-describedby=\"email-error\">\n    <p id=\"email-error\" class=\"error\" role=\"alert\">\n      Please enter a valid email address (e.g., name@example.com)\n    </p>\n  </div>\n</form>\n```\n\n```javascript\n// Focus first error on submit\nform.addEventListener('submit', (e) => {\n  const firstError = form.querySelector('[aria-invalid=\"true\"]');\n  if (firstError) {\n    e.preventDefault();\n    firstError.focus();\n    \n    // Announce error summary\n    const errorSummary = document.getElementById('error-summary');\n    errorSummary.textContent = `${errors.length} errors found. Please fix them and try again.`;\n    errorSummary.focus();\n  }\n});\n```\n\n---\n\n## Robust\n\n### Valid HTML (4.1.1)\n\n```html\n<!-- ❌ Duplicate IDs -->\n<div id=\"content\">...</div>\n<div id=\"content\">...</div>\n\n<!-- ❌ Invalid nesting -->\n<a href=\"/\"><button>Click</button></a>\n\n<!-- ✅ Unique IDs -->\n<div id=\"main-content\">...</div>\n<div id=\"sidebar-content\">...</div>\n\n<!-- ✅ Proper nesting -->\n<a href=\"/\" class=\"button-link\">Click</a>\n```\n\n### ARIA usage (4.1.2)\n\n**Prefer native elements:**\n```html\n<!-- ❌ ARIA role on div -->\n<div role=\"button\" tabindex=\"0\">Click me</div>\n\n<!-- ✅ Native button -->\n<button>Click me</button>\n\n<!-- ❌ ARIA checkbox -->\n<div role=\"checkbox\" aria-checked=\"false\">Option</div>\n\n<!-- ✅ Native checkbox -->\n<label><input type=\"checkbox\"> Option</label>\n```\n\n**When ARIA is needed:**\n```html\n<!-- Custom tabs component -->\n<div role=\"tablist\" aria-label=\"Product information\">\n  <button role=\"tab\" id=\"tab-1\" aria-selected=\"true\" \n          aria-controls=\"panel-1\">Description</button>\n  <button role=\"tab\" id=\"tab-2\" aria-selected=\"false\" \n          aria-controls=\"panel-2\" tabindex=\"-1\">Reviews</button>\n</div>\n<div role=\"tabpanel\" id=\"panel-1\" aria-labelledby=\"tab-1\">\n  <!-- Panel content -->\n</div>\n<div role=\"tabpanel\" id=\"panel-2\" aria-labelledby=\"tab-2\" hidden>\n  <!-- Panel content -->\n</div>\n```\n\n### Live regions (4.1.3)\n\n```html\n<!-- Status updates -->\n<div aria-live=\"polite\" aria-atomic=\"true\" class=\"status\">\n  <!-- Content updates announced to screen readers -->\n</div>\n\n<!-- Urgent alerts -->\n<div role=\"alert\" aria-live=\"assertive\">\n  <!-- Interrupts current announcement -->\n</div>\n```\n\n```javascript\n// Announce dynamic content changes\nfunction showNotification(message, type = 'polite') {\n  const container = document.getElementById(`${type}-announcer`);\n  container.textContent = ''; // Clear first\n  requestAnimationFrame(() => {\n    container.textContent = message;\n  });\n}\n```\n\n---\n\n## Testing checklist\n\n### Automated testing\n```bash\n# Lighthouse accessibility audit\nnpx lighthouse https://example.com --only-categories=accessibility\n\n# axe-core\nnpm install @axe-core/cli -g\naxe https://example.com\n```\n\n### Manual testing\n\n- [ ] **Keyboard navigation:** Tab through entire page, use Enter/Space to activate\n- [ ] **Screen reader:** Test with VoiceOver (Mac), NVDA (Windows), or TalkBack (Android)\n- [ ] **Zoom:** Content usable at 200% zoom\n- [ ] **High contrast:** Test with Windows High Contrast Mode\n- [ ] **Reduced motion:** Test with `prefers-reduced-motion: reduce`\n- [ ] **Focus order:** Logical and follows visual order\n\n### Screen reader commands\n\n| Action | VoiceOver (Mac) | NVDA (Windows) |\n|--------|-----------------|----------------|\n| Start/Stop | ⌘ + F5 | Ctrl + Alt + N |\n| Next item | VO + → | ↓ |\n| Previous item | VO + ← | ↑ |\n| Activate | VO + Space | Enter |\n| Headings list | VO + U, then arrows | H / Shift + H |\n| Links list | VO + U | K / Shift + K |\n\n---\n\n## Common issues by impact\n\n### Critical (fix immediately)\n1. Missing form labels\n2. Missing image alt text\n3. Insufficient color contrast\n4. Keyboard traps\n5. No focus indicators\n\n### Serious (fix before launch)\n1. Missing page language\n2. Missing heading structure\n3. Non-descriptive link text\n4. Auto-playing media\n5. Missing skip links\n\n### Moderate (fix soon)\n1. Missing ARIA labels on icons\n2. Inconsistent navigation\n3. Missing error identification\n4. Timing without controls\n5. Missing landmark regions\n\n## References\n\n- [WCAG 2.1 Quick Reference](https://www.w3.org/WAI/WCAG21/quickref/)\n- [WAI-ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/)\n- [Deque axe Rules](https://dequeuniversity.com/rules/axe/)\n- [Web Quality Audit](../web-quality-audit/SKILL.md)\n","src/resources/skills/accessibility/references/WCAG.md":"# WCAG 2.1 Quick Reference\n\n## Success criteria by level\n\n### Level A (minimum)\n\n| Criterion | Description |\n|-----------|-------------|\n| **1.1.1** Non-text Content | All images, icons have text alternatives |\n| **1.2.1** Audio-only/Video-only | Provide transcript or audio description |\n| **1.2.2** Captions | Video with audio has captions |\n| **1.2.3** Audio Description | Video has audio description |\n| **1.3.1** Info and Relationships | Information conveyed through presentation is available programmatically |\n| **1.3.2** Meaningful Sequence | Reading order is logical |\n| **1.3.3** Sensory Characteristics | Instructions don't rely solely on shape, color, size, location, orientation, or sound |\n| **1.4.1** Use of Color | Color is not the only visual means of conveying information |\n| **1.4.2** Audio Control | Audio playing automatically can be paused/stopped |\n| **2.1.1** Keyboard | All functionality available via keyboard |\n| **2.1.2** No Keyboard Trap | Keyboard focus can be moved away from any component |\n| **2.1.4** Character Key Shortcuts | Single-key shortcuts can be turned off or remapped |\n| **2.2.1** Timing Adjustable | Time limits can be extended |\n| **2.2.2** Pause, Stop, Hide | Moving/blinking content can be paused |\n| **2.3.1** Three Flashes | Nothing flashes more than 3 times per second |\n| **2.4.1** Bypass Blocks | Skip link or landmark navigation available |\n| **2.4.2** Page Titled | Pages have descriptive titles |\n| **2.4.3** Focus Order | Focus order preserves meaning |\n| **2.4.4** Link Purpose | Link purpose clear from link text or context |\n| **2.5.1** Pointer Gestures | Multi-point gestures have single-pointer alternatives |\n| **2.5.2** Pointer Cancellation | Down-event doesn't trigger action (use up-event or click) |\n| **2.5.3** Label in Name | Accessible name contains visible label text |\n| **2.5.4** Motion Actuation | Motion-triggered functions have alternatives |\n| **3.1.1** Language of Page | Default language specified in HTML |\n| **3.2.1** On Focus | Focus doesn't trigger unexpected changes |\n| **3.2.2** On Input | Input doesn't trigger unexpected changes |\n| **3.3.1** Error Identification | Input errors clearly described |\n| **3.3.2** Labels or Instructions | Form inputs have labels or instructions |\n| **4.1.1** Parsing | HTML is well-formed (no duplicate IDs, proper nesting) |\n| **4.1.2** Name, Role, Value | UI components have accessible names and correct roles |\n\n### Level AA (standard)\n\n| Criterion | Description |\n|-----------|-------------|\n| **1.2.4** Captions (Live) | Live audio has captions |\n| **1.2.5** Audio Description | Pre-recorded video has audio description |\n| **1.3.4** Orientation | Content doesn't restrict orientation |\n| **1.3.5** Identify Input Purpose | Input purpose can be programmatically determined |\n| **1.4.3** Contrast (Minimum) | 4.5:1 for normal text, 3:1 for large text |\n| **1.4.4** Resize Text | Text can be resized to 200% without loss of functionality |\n| **1.4.5** Images of Text | Text used instead of images of text |\n| **1.4.10** Reflow | Content reflows at 320px width without horizontal scroll |\n| **1.4.11** Non-text Contrast | UI components have 3:1 contrast |\n| **1.4.12** Text Spacing | Content adapts to text spacing changes |\n| **1.4.13** Content on Hover/Focus | Additional content is dismissible, hoverable, persistent |\n| **2.4.5** Multiple Ways | Multiple ways to find pages |\n| **2.4.6** Headings and Labels | Headings and labels are descriptive |\n| **2.4.7** Focus Visible | Focus indicator is visible |\n| **3.1.2** Language of Parts | Language changes are marked |\n| **3.2.3** Consistent Navigation | Navigation is consistent across pages |\n| **3.2.4** Consistent Identification | Same functionality uses same labels |\n| **3.3.3** Error Suggestion | Error corrections suggested when known |\n| **3.3.4** Error Prevention (Legal) | Actions can be reversed or confirmed |\n| **4.1.3** Status Messages | Status messages announced to screen readers |\n\n### Level AAA (enhanced)\n\n| Criterion | Description |\n|-----------|-------------|\n| **1.4.6** Contrast (Enhanced) | 7:1 for normal text, 4.5:1 for large text |\n| **1.4.8** Visual Presentation | Foreground/background colors can be selected |\n| **1.4.9** Images of Text (No Exception) | No images of text |\n| **2.1.3** Keyboard (No Exception) | All functionality keyboard accessible |\n| **2.2.3** No Timing | No time limits |\n| **2.2.4** Interruptions | Interruptions can be postponed |\n| **2.2.5** Re-authenticating | Data preserved on re-authentication |\n| **2.2.6** Timeouts | Users warned about data loss from inactivity |\n| **2.3.2** Three Flashes | No content flashes more than 3 times |\n| **2.3.3** Animation from Interactions | Motion animation can be disabled |\n| **2.4.8** Location | User location within site is available |\n| **2.4.9** Link Purpose (Link Only) | Link purpose clear from link text alone |\n| **2.4.10** Section Headings | Sections have headings |\n| **3.1.3** Unusual Words | Definitions available for unusual words |\n| **3.1.4** Abbreviations | Abbreviations expanded |\n| **3.1.5** Reading Level | Alternative content for complex text |\n| **3.1.6** Pronunciation | Pronunciation available where needed |\n| **3.2.5** Change on Request | Changes initiated only by user |\n| **3.3.5** Help | Context-sensitive help available |\n| **3.3.6** Error Prevention (All) | All form submissions can be reviewed |\n\n## Common ARIA patterns\n\n### Buttons\n```html\n<button>Label</button>\n<!-- or -->\n<button aria-label=\"Close dialog\">×</button>\n```\n\n### Links\n```html\n<a href=\"/page\">Descriptive link text</a>\n<!-- External links -->\n<a href=\"https://external.com\" target=\"_blank\" rel=\"noopener\">\n  External site\n  <span class=\"visually-hidden\">(opens in new tab)</span>\n</a>\n```\n\n### Form fields\n```html\n<label for=\"email\">Email address</label>\n<input type=\"email\" id=\"email\" aria-describedby=\"email-hint\">\n<p id=\"email-hint\">We'll never share your email.</p>\n```\n\n### Error states\n```html\n<label for=\"email\">Email</label>\n<input type=\"email\" id=\"email\" aria-invalid=\"true\" aria-describedby=\"email-error\">\n<p id=\"email-error\" role=\"alert\">Please enter a valid email address.</p>\n```\n\n### Navigation\n```html\n<nav aria-label=\"Main\">\n  <ul>\n    <li><a href=\"/\" aria-current=\"page\">Home</a></li>\n    <li><a href=\"/about\">About</a></li>\n  </ul>\n</nav>\n```\n\n### Modals\n```html\n<div role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"dialog-title\">\n  <h2 id=\"dialog-title\">Confirm Action</h2>\n  <!-- content -->\n</div>\n```\n\n### Live regions\n```html\n<!-- Polite (waits for pause in speech) -->\n<div aria-live=\"polite\">Status update here</div>\n\n<!-- Assertive (interrupts immediately) -->\n<div aria-live=\"assertive\" role=\"alert\">Error message here</div>\n\n<!-- Status (polite, implicit) -->\n<div role=\"status\">Loading complete</div>\n```\n\n## Testing tools\n\n| Tool | Type | URL |\n|------|------|-----|\n| axe DevTools | Browser extension | [deque.com/axe](https://www.deque.com/axe/) |\n| WAVE | Browser extension | [wave.webaim.org](https://wave.webaim.org/) |\n| Lighthouse | Built into Chrome | DevTools → Lighthouse |\n| NVDA | Screen reader (Windows) | [nvaccess.org](https://www.nvaccess.org/) |\n| VoiceOver | Screen reader (Mac) | Built into macOS |\n| Colour Contrast Analyser | Desktop app | [tpgi.com](https://www.tpgi.com/color-contrast-checker/) |\n","src/resources/skills/agent-browser/SKILL.md":"---\nname: agent-browser\ndescription: Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to \"open a website\", \"fill out a form\", \"click a button\", \"take a screenshot\", \"scrape data from a page\", \"test this web app\", \"login to a site\", \"automate browser actions\", or any task requiring programmatic web interaction.\nallowed-tools: Bash(npx agent-browser:*), Bash(agent-browser:*)\n---\n\n# Browser Automation with agent-browser\n\n## Core Workflow\n\nEvery browser automation follows this pattern:\n\n1. **Navigate**: `agent-browser open <url>`\n2. **Snapshot**: `agent-browser snapshot -i` (get element refs like `@e1`, `@e2`)\n3. **Interact**: Use refs to click, fill, select\n4. **Re-snapshot**: After navigation or DOM changes, get fresh refs\n\n```bash\nagent-browser open https://example.com/form\nagent-browser snapshot -i\n# Output: @e1 [input type=\"email\"], @e2 [input type=\"password\"], @e3 [button] \"Submit\"\n\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\nagent-browser click @e3\nagent-browser wait --load networkidle\nagent-browser snapshot -i  # Check result\n```\n\n## Command Chaining\n\nCommands can be chained with `&&` in a single shell invocation. The browser persists between commands via a background daemon, so chaining is safe and more efficient than separate calls.\n\n```bash\n# Chain open + wait + snapshot in one call\nagent-browser open https://example.com && agent-browser wait --load networkidle && agent-browser snapshot -i\n\n# Chain multiple interactions\nagent-browser fill @e1 \"user@example.com\" && agent-browser fill @e2 \"password123\" && agent-browser click @e3\n\n# Navigate and capture\nagent-browser open https://example.com && agent-browser wait --load networkidle && agent-browser screenshot page.png\n```\n\n**When to chain:** Use `&&` when you don't need to read the output of an intermediate command before proceeding (e.g., open + wait + screenshot). Run commands separately when you need to parse the output first (e.g., snapshot to discover refs, then interact using those refs).\n\n## Essential Commands\n\n```bash\n# Navigation\nagent-browser open <url>              # Navigate (aliases: goto, navigate)\nagent-browser close                   # Close browser\n\n# Snapshot\nagent-browser snapshot -i             # Interactive elements with refs (recommended)\nagent-browser snapshot -i -C          # Include cursor-interactive elements (divs with onclick, cursor:pointer)\nagent-browser snapshot -s \"#selector\" # Scope to CSS selector\n\n# Interaction (use @refs from snapshot)\nagent-browser click @e1               # Click element\nagent-browser click @e1 --new-tab     # Click and open in new tab\nagent-browser fill @e2 \"text\"         # Clear and type text\nagent-browser type @e2 \"text\"         # Type without clearing\nagent-browser select @e1 \"option\"     # Select dropdown option\nagent-browser check @e1               # Check checkbox\nagent-browser press Enter             # Press key\nagent-browser keyboard type \"text\"    # Type at current focus (no selector)\nagent-browser keyboard inserttext \"text\"  # Insert without key events\nagent-browser scroll down 500         # Scroll page\nagent-browser scroll down 500 --selector \"div.content\"  # Scroll within a specific container\n\n# Get information\nagent-browser get text @e1            # Get element text\nagent-browser get url                 # Get current URL\nagent-browser get title               # Get page title\n\n# Wait\nagent-browser wait @e1                # Wait for element\nagent-browser wait --load networkidle # Wait for network idle\nagent-browser wait --url \"**/page\"    # Wait for URL pattern\nagent-browser wait 2000               # Wait milliseconds\n\n# Downloads\nagent-browser download @e1 ./file.pdf          # Click element to trigger download\nagent-browser wait --download ./output.zip     # Wait for any download to complete\nagent-browser --download-path ./downloads open <url>  # Set default download directory\n\n# Capture\nagent-browser screenshot              # Screenshot to temp dir\nagent-browser screenshot --full       # Full page screenshot\nagent-browser screenshot --annotate   # Annotated screenshot with numbered element labels\nagent-browser pdf output.pdf          # Save as PDF\n\n# Diff (compare page states)\nagent-browser diff snapshot                          # Compare current vs last snapshot\nagent-browser diff snapshot --baseline before.txt    # Compare current vs saved file\nagent-browser diff screenshot --baseline before.png  # Visual pixel diff\nagent-browser diff url <url1> <url2>                 # Compare two pages\nagent-browser diff url <url1> <url2> --wait-until networkidle  # Custom wait strategy\nagent-browser diff url <url1> <url2> --selector \"#main\"  # Scope to element\n```\n\n## Common Patterns\n\n### Form Submission\n\n```bash\nagent-browser open https://example.com/signup\nagent-browser snapshot -i\nagent-browser fill @e1 \"Jane Doe\"\nagent-browser fill @e2 \"jane@example.com\"\nagent-browser select @e3 \"California\"\nagent-browser check @e4\nagent-browser click @e5\nagent-browser wait --load networkidle\n```\n\n### Authentication with Auth Vault (Recommended)\n\n```bash\n# Save credentials once (encrypted with AGENT_BROWSER_ENCRYPTION_KEY)\n# Recommended: pipe password via stdin to avoid shell history exposure\necho \"pass\" | agent-browser auth save github --url https://github.com/login --username user --password-stdin\n\n# Login using saved profile (LLM never sees password)\nagent-browser auth login github\n\n# List/show/delete profiles\nagent-browser auth list\nagent-browser auth show github\nagent-browser auth delete github\n```\n\n### Authentication with State Persistence\n\n```bash\n# Login once and save state\nagent-browser open https://app.example.com/login\nagent-browser snapshot -i\nagent-browser fill @e1 \"$USERNAME\"\nagent-browser fill @e2 \"$PASSWORD\"\nagent-browser click @e3\nagent-browser wait --url \"**/dashboard\"\nagent-browser state save auth.json\n\n# Reuse in future sessions\nagent-browser state load auth.json\nagent-browser open https://app.example.com/dashboard\n```\n\n### Session Persistence\n\n```bash\n# Auto-save/restore cookies and localStorage across browser restarts\nagent-browser --session-name myapp open https://app.example.com/login\n# ... login flow ...\nagent-browser close  # State auto-saved to ~/.agent-browser/sessions/\n\n# Next time, state is auto-loaded\nagent-browser --session-name myapp open https://app.example.com/dashboard\n\n# Encrypt state at rest\nexport AGENT_BROWSER_ENCRYPTION_KEY=$(openssl rand -hex 32)\nagent-browser --session-name secure open https://app.example.com\n\n# Manage saved states\nagent-browser state list\nagent-browser state show myapp-default.json\nagent-browser state clear myapp\nagent-browser state clean --older-than 7\n```\n\n### Data Extraction\n\n```bash\nagent-browser open https://example.com/products\nagent-browser snapshot -i\nagent-browser get text @e5           # Get specific element text\nagent-browser get text body > page.txt  # Get all page text\n\n# JSON output for parsing\nagent-browser snapshot -i --json\nagent-browser get text @e1 --json\n```\n\n### Parallel Sessions\n\n```bash\nagent-browser --session site1 open https://site-a.com\nagent-browser --session site2 open https://site-b.com\n\nagent-browser --session site1 snapshot -i\nagent-browser --session site2 snapshot -i\n\nagent-browser session list\n```\n\n### Connect to Existing Chrome\n\n```bash\n# Auto-discover running Chrome with remote debugging enabled\nagent-browser --auto-connect open https://example.com\nagent-browser --auto-connect snapshot\n\n# Or with explicit CDP port\nagent-browser --cdp 9222 snapshot\n```\n\n### Color Scheme (Dark Mode)\n\n```bash\n# Persistent dark mode via flag (applies to all pages and new tabs)\nagent-browser --color-scheme dark open https://example.com\n\n# Or via environment variable\nAGENT_BROWSER_COLOR_SCHEME=dark agent-browser open https://example.com\n\n# Or set during session (persists for subsequent commands)\nagent-browser set media dark\n```\n\n### Visual Browser (Debugging)\n\n```bash\nagent-browser --headed open https://example.com\nagent-browser highlight @e1          # Highlight element\nagent-browser record start demo.webm # Record session\nagent-browser profiler start         # Start Chrome DevTools profiling\nagent-browser profiler stop trace.json # Stop and save profile (path optional)\n```\n\nUse `AGENT_BROWSER_HEADED=1` to enable headed mode via environment variable. Browser extensions work in both headed and headless mode.\n\n### Local Files (PDFs, HTML)\n\n```bash\n# Open local files with file:// URLs\nagent-browser --allow-file-access open file:///path/to/document.pdf\nagent-browser --allow-file-access open file:///path/to/page.html\nagent-browser screenshot output.png\n```\n\n### iOS Simulator (Mobile Safari)\n\n```bash\n# List available iOS simulators\nagent-browser device list\n\n# Launch Safari on a specific device\nagent-browser -p ios --device \"iPhone 16 Pro\" open https://example.com\n\n# Same workflow as desktop - snapshot, interact, re-snapshot\nagent-browser -p ios snapshot -i\nagent-browser -p ios tap @e1          # Tap (alias for click)\nagent-browser -p ios fill @e2 \"text\"\nagent-browser -p ios swipe up         # Mobile-specific gesture\n\n# Take screenshot\nagent-browser -p ios screenshot mobile.png\n\n# Close session (shuts down simulator)\nagent-browser -p ios close\n```\n\n**Requirements:** macOS with Xcode, Appium (`npm install -g appium && appium driver install xcuitest`)\n\n**Real devices:** Works with physical iOS devices if pre-configured. Use `--device \"<UDID>\"` where UDID is from `xcrun xctrace list devices`.\n\n## Security\n\nAll security features are opt-in. By default, agent-browser imposes no restrictions on navigation, actions, or output.\n\n### Content Boundaries (Recommended for AI Agents)\n\nEnable `--content-boundaries` to wrap page-sourced output in markers that help LLMs distinguish tool output from untrusted page content:\n\n```bash\nexport AGENT_BROWSER_CONTENT_BOUNDARIES=1\nagent-browser snapshot\n# Output:\n# --- AGENT_BROWSER_PAGE_CONTENT nonce=<hex> origin=https://example.com ---\n# [accessibility tree]\n# --- END_AGENT_BROWSER_PAGE_CONTENT nonce=<hex> ---\n```\n\n### Domain Allowlist\n\nRestrict navigation to trusted domains. Wildcards like `*.example.com` also match the bare domain `example.com`. Sub-resource requests, WebSocket, and EventSource connections to non-allowed domains are also blocked. Include CDN domains your target pages depend on:\n\n```bash\nexport AGENT_BROWSER_ALLOWED_DOMAINS=\"example.com,*.example.com\"\nagent-browser open https://example.com        # OK\nagent-browser open https://malicious.com       # Blocked\n```\n\n### Action Policy\n\nUse a policy file to gate destructive actions:\n\n```bash\nexport AGENT_BROWSER_ACTION_POLICY=./policy.json\n```\n\nExample `policy.json`:\n```json\n{\"default\": \"deny\", \"allow\": [\"navigate\", \"snapshot\", \"click\", \"scroll\", \"wait\", \"get\"]}\n```\n\nAuth vault operations (`auth login`, etc.) bypass action policy but domain allowlist still applies.\n\n### Output Limits\n\nPrevent context flooding from large pages:\n\n```bash\nexport AGENT_BROWSER_MAX_OUTPUT=50000\n```\n\n## Diffing (Verifying Changes)\n\nUse `diff snapshot` after performing an action to verify it had the intended effect. This compares the current accessibility tree against the last snapshot taken in the session.\n\n```bash\n# Typical workflow: snapshot -> action -> diff\nagent-browser snapshot -i          # Take baseline snapshot\nagent-browser click @e2            # Perform action\nagent-browser diff snapshot        # See what changed (auto-compares to last snapshot)\n```\n\nFor visual regression testing or monitoring:\n\n```bash\n# Save a baseline screenshot, then compare later\nagent-browser screenshot baseline.png\n# ... time passes or changes are made ...\nagent-browser diff screenshot --baseline baseline.png\n\n# Compare staging vs production\nagent-browser diff url https://staging.example.com https://prod.example.com --screenshot\n```\n\n`diff snapshot` output uses `+` for additions and `-` for removals, similar to git diff. `diff screenshot` produces a diff image with changed pixels highlighted in red, plus a mismatch percentage.\n\n## Timeouts and Slow Pages\n\nThe default Playwright timeout is 25 seconds for local browsers. This can be overridden with the `AGENT_BROWSER_DEFAULT_TIMEOUT` environment variable (value in milliseconds). For slow websites or large pages, use explicit waits instead of relying on the default timeout:\n\n```bash\n# Wait for network activity to settle (best for slow pages)\nagent-browser wait --load networkidle\n\n# Wait for a specific element to appear\nagent-browser wait \"#content\"\nagent-browser wait @e1\n\n# Wait for a specific URL pattern (useful after redirects)\nagent-browser wait --url \"**/dashboard\"\n\n# Wait for a JavaScript condition\nagent-browser wait --fn \"document.readyState === 'complete'\"\n\n# Wait a fixed duration (milliseconds) as a last resort\nagent-browser wait 5000\n```\n\nWhen dealing with consistently slow websites, use `wait --load networkidle` after `open` to ensure the page is fully loaded before taking a snapshot. If a specific element is slow to render, wait for it directly with `wait <selector>` or `wait @ref`.\n\n## Session Management and Cleanup\n\nWhen running multiple agents or automations concurrently, always use named sessions to avoid conflicts:\n\n```bash\n# Each agent gets its own isolated session\nagent-browser --session agent1 open site-a.com\nagent-browser --session agent2 open site-b.com\n\n# Check active sessions\nagent-browser session list\n```\n\nAlways close your browser session when done to avoid leaked processes:\n\n```bash\nagent-browser close                    # Close default session\nagent-browser --session agent1 close   # Close specific session\n```\n\nIf a previous session was not closed properly, the daemon may still be running. Use `agent-browser close` to clean it up before starting new work.\n\n## Ref Lifecycle (Important)\n\nRefs (`@e1`, `@e2`, etc.) are invalidated when the page changes. Always re-snapshot after:\n\n- Clicking links or buttons that navigate\n- Form submissions\n- Dynamic content loading (dropdowns, modals)\n\n```bash\nagent-browser click @e5              # Navigates to new page\nagent-browser snapshot -i            # MUST re-snapshot\nagent-browser click @e1              # Use new refs\n```\n\n## Annotated Screenshots (Vision Mode)\n\nUse `--annotate` to take a screenshot with numbered labels overlaid on interactive elements. Each label `[N]` maps to ref `@eN`. This also caches refs, so you can interact with elements immediately without a separate snapshot.\n\n```bash\nagent-browser screenshot --annotate\n# Output includes the image path and a legend:\n#   [1] @e1 button \"Submit\"\n#   [2] @e2 link \"Home\"\n#   [3] @e3 textbox \"Email\"\nagent-browser click @e2              # Click using ref from annotated screenshot\n```\n\nUse annotated screenshots when:\n- The page has unlabeled icon buttons or visual-only elements\n- You need to verify visual layout or styling\n- Canvas or chart elements are present (invisible to text snapshots)\n- You need spatial reasoning about element positions\n\n## Semantic Locators (Alternative to Refs)\n\nWhen refs are unavailable or unreliable, use semantic locators:\n\n```bash\nagent-browser find text \"Sign In\" click\nagent-browser find label \"Email\" fill \"user@test.com\"\nagent-browser find role button click --name \"Submit\"\nagent-browser find placeholder \"Search\" type \"query\"\nagent-browser find testid \"submit-btn\" click\n```\n\n## JavaScript Evaluation (eval)\n\nUse `eval` to run JavaScript in the browser context. **Shell quoting can corrupt complex expressions** -- use `--stdin` or `-b` to avoid issues.\n\n```bash\n# Simple expressions work with regular quoting\nagent-browser eval 'document.title'\nagent-browser eval 'document.querySelectorAll(\"img\").length'\n\n# Complex JS: use --stdin with heredoc (RECOMMENDED)\nagent-browser eval --stdin <<'EVALEOF'\nJSON.stringify(\n  Array.from(document.querySelectorAll(\"img\"))\n    .filter(i => !i.alt)\n    .map(i => ({ src: i.src.split(\"/\").pop(), width: i.width }))\n)\nEVALEOF\n\n# Alternative: base64 encoding (avoids all shell escaping issues)\nagent-browser eval -b \"$(echo -n 'Array.from(document.querySelectorAll(\"a\")).map(a => a.href)' | base64)\"\n```\n\n**Why this matters:** When the shell processes your command, inner double quotes, `!` characters (history expansion), backticks, and `$()` can all corrupt the JavaScript before it reaches agent-browser. The `--stdin` and `-b` flags bypass shell interpretation entirely.\n\n**Rules of thumb:**\n- Single-line, no nested quotes -> regular `eval 'expression'` with single quotes is fine\n- Nested quotes, arrow functions, template literals, or multiline -> use `eval --stdin <<'EVALEOF'`\n- Programmatic/generated scripts -> use `eval -b` with base64\n\n## Configuration File\n\nCreate `agent-browser.json` in the project root for persistent settings:\n\n```json\n{\n  \"headed\": true,\n  \"proxy\": \"http://localhost:8080\",\n  \"profile\": \"./browser-data\"\n}\n```\n\nPriority (lowest to highest): `~/.agent-browser/config.json` < `./agent-browser.json` < env vars < CLI flags. Use `--config <path>` or `AGENT_BROWSER_CONFIG` env var for a custom config file (exits with error if missing/invalid). All CLI options map to camelCase keys (e.g., `--executable-path` -> `\"executablePath\"`). Boolean flags accept `true`/`false` values (e.g., `--headed false` overrides config). Extensions from user and project configs are merged, not replaced.\n\n## Deep-Dive Documentation\n\n| Reference | When to Use |\n|-----------|-------------|\n| [references/commands.md](references/commands.md) | Full command reference with all options |\n| [references/snapshot-refs.md](references/snapshot-refs.md) | Ref lifecycle, invalidation rules, troubleshooting |\n| [references/session-management.md](references/session-management.md) | Parallel sessions, state persistence, concurrent scraping |\n| [references/authentication.md](references/authentication.md) | Login flows, OAuth, 2FA handling, state reuse |\n| [references/video-recording.md](references/video-recording.md) | Recording workflows for debugging and documentation |\n| [references/profiling.md](references/profiling.md) | Chrome DevTools profiling for performance analysis |\n| [references/proxy-support.md](references/proxy-support.md) | Proxy configuration, geo-testing, rotating proxies |\n\n## Experimental: Native Mode\n\nagent-browser has an experimental native Rust daemon that communicates with Chrome directly via CDP, bypassing Node.js and Playwright entirely. It is opt-in and not recommended for production use yet.\n\n```bash\n# Enable via flag\nagent-browser --native open example.com\n\n# Enable via environment variable (avoids passing --native every time)\nexport AGENT_BROWSER_NATIVE=1\nagent-browser open example.com\n```\n\nThe native daemon supports Chromium and Safari (via WebDriver). Firefox and WebKit are not yet supported. All core commands (navigate, snapshot, click, fill, screenshot, cookies, storage, tabs, eval, etc.) work identically in native mode. Use `agent-browser close` before switching between native and default mode within the same session.\n\n## Ready-to-Use Templates\n\n| Template | Description |\n|----------|-------------|\n| [templates/form-automation.sh](templates/form-automation.sh) | Form filling with validation |\n| [templates/authenticated-session.sh](templates/authenticated-session.sh) | Login once, reuse state |\n| [templates/capture-workflow.sh](templates/capture-workflow.sh) | Content extraction with screenshots |\n\n```bash\n./templates/form-automation.sh https://example.com/form\n./templates/authenticated-session.sh https://app.example.com/login\n./templates/capture-workflow.sh https://example.com ./output\n```\n","src/resources/skills/agent-browser/references/authentication.md":"# Authentication Patterns\n\nLogin flows, session persistence, OAuth, 2FA, and authenticated browsing.\n\n**Related**: [session-management.md](session-management.md) for state persistence details, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Login Flow](#basic-login-flow)\n- [Saving Authentication State](#saving-authentication-state)\n- [Restoring Authentication](#restoring-authentication)\n- [OAuth / SSO Flows](#oauth--sso-flows)\n- [Two-Factor Authentication](#two-factor-authentication)\n- [HTTP Basic Auth](#http-basic-auth)\n- [Cookie-Based Auth](#cookie-based-auth)\n- [Token Refresh Handling](#token-refresh-handling)\n- [Security Best Practices](#security-best-practices)\n\n## Basic Login Flow\n\n```bash\n# Navigate to login page\nagent-browser open https://app.example.com/login\nagent-browser wait --load networkidle\n\n# Get form elements\nagent-browser snapshot -i\n# Output: @e1 [input type=\"email\"], @e2 [input type=\"password\"], @e3 [button] \"Sign In\"\n\n# Fill credentials\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\n\n# Submit\nagent-browser click @e3\nagent-browser wait --load networkidle\n\n# Verify login succeeded\nagent-browser get url  # Should be dashboard, not login\n```\n\n## Saving Authentication State\n\nAfter logging in, save state for reuse:\n\n```bash\n# Login first (see above)\nagent-browser open https://app.example.com/login\nagent-browser snapshot -i\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\nagent-browser click @e3\nagent-browser wait --url \"**/dashboard\"\n\n# Save authenticated state\nagent-browser state save ./auth-state.json\n```\n\n## Restoring Authentication\n\nSkip login by loading saved state:\n\n```bash\n# Load saved auth state\nagent-browser state load ./auth-state.json\n\n# Navigate directly to protected page\nagent-browser open https://app.example.com/dashboard\n\n# Verify authenticated\nagent-browser snapshot -i\n```\n\n## OAuth / SSO Flows\n\nFor OAuth redirects:\n\n```bash\n# Start OAuth flow\nagent-browser open https://app.example.com/auth/google\n\n# Handle redirects automatically\nagent-browser wait --url \"**/accounts.google.com**\"\nagent-browser snapshot -i\n\n# Fill Google credentials\nagent-browser fill @e1 \"user@gmail.com\"\nagent-browser click @e2  # Next button\nagent-browser wait 2000\nagent-browser snapshot -i\nagent-browser fill @e3 \"password\"\nagent-browser click @e4  # Sign in\n\n# Wait for redirect back\nagent-browser wait --url \"**/app.example.com**\"\nagent-browser state save ./oauth-state.json\n```\n\n## Two-Factor Authentication\n\nHandle 2FA with manual intervention:\n\n```bash\n# Login with credentials\nagent-browser open https://app.example.com/login --headed  # Show browser\nagent-browser snapshot -i\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\nagent-browser click @e3\n\n# Wait for user to complete 2FA manually\necho \"Complete 2FA in the browser window...\"\nagent-browser wait --url \"**/dashboard\" --timeout 120000\n\n# Save state after 2FA\nagent-browser state save ./2fa-state.json\n```\n\n## HTTP Basic Auth\n\nFor sites using HTTP Basic Authentication:\n\n```bash\n# Set credentials before navigation\nagent-browser set credentials username password\n\n# Navigate to protected resource\nagent-browser open https://protected.example.com/api\n```\n\n## Cookie-Based Auth\n\nManually set authentication cookies:\n\n```bash\n# Set auth cookie\nagent-browser cookies set session_token \"abc123xyz\"\n\n# Navigate to protected page\nagent-browser open https://app.example.com/dashboard\n```\n\n## Token Refresh Handling\n\nFor sessions with expiring tokens:\n\n```bash\n#!/bin/bash\n# Wrapper that handles token refresh\n\nSTATE_FILE=\"./auth-state.json\"\n\n# Try loading existing state\nif [[ -f \"$STATE_FILE\" ]]; then\n    agent-browser state load \"$STATE_FILE\"\n    agent-browser open https://app.example.com/dashboard\n\n    # Check if session is still valid\n    URL=$(agent-browser get url)\n    if [[ \"$URL\" == *\"/login\"* ]]; then\n        echo \"Session expired, re-authenticating...\"\n        # Perform fresh login\n        agent-browser snapshot -i\n        agent-browser fill @e1 \"$USERNAME\"\n        agent-browser fill @e2 \"$PASSWORD\"\n        agent-browser click @e3\n        agent-browser wait --url \"**/dashboard\"\n        agent-browser state save \"$STATE_FILE\"\n    fi\nelse\n    # First-time login\n    agent-browser open https://app.example.com/login\n    # ... login flow ...\nfi\n```\n\n## Security Best Practices\n\n1. **Never commit state files** - They contain session tokens\n   ```bash\n   echo \"*.auth-state.json\" >> .gitignore\n   ```\n\n2. **Use environment variables for credentials**\n   ```bash\n   agent-browser fill @e1 \"$APP_USERNAME\"\n   agent-browser fill @e2 \"$APP_PASSWORD\"\n   ```\n\n3. **Clean up after automation**\n   ```bash\n   agent-browser cookies clear\n   rm -f ./auth-state.json\n   ```\n\n4. **Use short-lived sessions for CI/CD**\n   ```bash\n   # Don't persist state in CI\n   agent-browser open https://app.example.com/login\n   # ... login and perform actions ...\n   agent-browser close  # Session ends, nothing persisted\n   ```\n","src/resources/skills/agent-browser/references/commands.md":"# Command Reference\n\nComplete reference for all agent-browser commands. For quick start and common patterns, see SKILL.md.\n\n## Navigation\n\n```bash\nagent-browser open <url>      # Navigate to URL (aliases: goto, navigate)\n                              # Supports: https://, http://, file://, about:, data://\n                              # Auto-prepends https:// if no protocol given\nagent-browser back            # Go back\nagent-browser forward         # Go forward\nagent-browser reload          # Reload page\nagent-browser close           # Close browser (aliases: quit, exit)\nagent-browser connect 9222    # Connect to browser via CDP port\n```\n\n## Snapshot (page analysis)\n\n```bash\nagent-browser snapshot            # Full accessibility tree\nagent-browser snapshot -i         # Interactive elements only (recommended)\nagent-browser snapshot -c         # Compact output\nagent-browser snapshot -d 3       # Limit depth to 3\nagent-browser snapshot -s \"#main\" # Scope to CSS selector\n```\n\n## Interactions (use @refs from snapshot)\n\n```bash\nagent-browser click @e1           # Click\nagent-browser click @e1 --new-tab # Click and open in new tab\nagent-browser dblclick @e1        # Double-click\nagent-browser focus @e1           # Focus element\nagent-browser fill @e2 \"text\"     # Clear and type\nagent-browser type @e2 \"text\"     # Type without clearing\nagent-browser press Enter         # Press key (alias: key)\nagent-browser press Control+a     # Key combination\nagent-browser keydown Shift       # Hold key down\nagent-browser keyup Shift         # Release key\nagent-browser hover @e1           # Hover\nagent-browser check @e1           # Check checkbox\nagent-browser uncheck @e1         # Uncheck checkbox\nagent-browser select @e1 \"value\"  # Select dropdown option\nagent-browser select @e1 \"a\" \"b\"  # Select multiple options\nagent-browser scroll down 500     # Scroll page (default: down 300px)\nagent-browser scrollintoview @e1  # Scroll element into view (alias: scrollinto)\nagent-browser drag @e1 @e2        # Drag and drop\nagent-browser upload @e1 file.pdf # Upload files\n```\n\n## Get Information\n\n```bash\nagent-browser get text @e1        # Get element text\nagent-browser get html @e1        # Get innerHTML\nagent-browser get value @e1       # Get input value\nagent-browser get attr @e1 href   # Get attribute\nagent-browser get title           # Get page title\nagent-browser get url             # Get current URL\nagent-browser get count \".item\"   # Count matching elements\nagent-browser get box @e1         # Get bounding box\nagent-browser get styles @e1      # Get computed styles (font, color, bg, etc.)\n```\n\n## Check State\n\n```bash\nagent-browser is visible @e1      # Check if visible\nagent-browser is enabled @e1      # Check if enabled\nagent-browser is checked @e1      # Check if checked\n```\n\n## Screenshots and PDF\n\n```bash\nagent-browser screenshot          # Save to temporary directory\nagent-browser screenshot path.png # Save to specific path\nagent-browser screenshot --full   # Full page\nagent-browser pdf output.pdf      # Save as PDF\n```\n\n## Video Recording\n\n```bash\nagent-browser record start ./demo.webm    # Start recording\nagent-browser click @e1                   # Perform actions\nagent-browser record stop                 # Stop and save video\nagent-browser record restart ./take2.webm # Stop current + start new\n```\n\n## Wait\n\n```bash\nagent-browser wait @e1                     # Wait for element\nagent-browser wait 2000                    # Wait milliseconds\nagent-browser wait --text \"Success\"        # Wait for text (or -t)\nagent-browser wait --url \"**/dashboard\"    # Wait for URL pattern (or -u)\nagent-browser wait --load networkidle      # Wait for network idle (or -l)\nagent-browser wait --fn \"window.ready\"     # Wait for JS condition (or -f)\n```\n\n## Mouse Control\n\n```bash\nagent-browser mouse move 100 200      # Move mouse\nagent-browser mouse down left         # Press button\nagent-browser mouse up left           # Release button\nagent-browser mouse wheel 100         # Scroll wheel\n```\n\n## Semantic Locators (alternative to refs)\n\n```bash\nagent-browser find role button click --name \"Submit\"\nagent-browser find text \"Sign In\" click\nagent-browser find text \"Sign In\" click --exact      # Exact match only\nagent-browser find label \"Email\" fill \"user@test.com\"\nagent-browser find placeholder \"Search\" type \"query\"\nagent-browser find alt \"Logo\" click\nagent-browser find title \"Close\" click\nagent-browser find testid \"submit-btn\" click\nagent-browser find first \".item\" click\nagent-browser find last \".item\" click\nagent-browser find nth 2 \"a\" hover\n```\n\n## Browser Settings\n\n```bash\nagent-browser set viewport 1920 1080          # Set viewport size\nagent-browser set device \"iPhone 14\"          # Emulate device\nagent-browser set geo 37.7749 -122.4194       # Set geolocation (alias: geolocation)\nagent-browser set offline on                  # Toggle offline mode\nagent-browser set headers '{\"X-Key\":\"v\"}'     # Extra HTTP headers\nagent-browser set credentials user pass       # HTTP basic auth (alias: auth)\nagent-browser set media dark                  # Emulate color scheme\nagent-browser set media light reduced-motion  # Light mode + reduced motion\n```\n\n## Cookies and Storage\n\n```bash\nagent-browser cookies                     # Get all cookies\nagent-browser cookies set name value      # Set cookie\nagent-browser cookies clear               # Clear cookies\nagent-browser storage local               # Get all localStorage\nagent-browser storage local key           # Get specific key\nagent-browser storage local set k v       # Set value\nagent-browser storage local clear         # Clear all\n```\n\n## Network\n\n```bash\nagent-browser network route <url>              # Intercept requests\nagent-browser network route <url> --abort      # Block requests\nagent-browser network route <url> --body '{}'  # Mock response\nagent-browser network unroute [url]            # Remove routes\nagent-browser network requests                 # View tracked requests\nagent-browser network requests --filter api    # Filter requests\n```\n\n## Tabs and Windows\n\n```bash\nagent-browser tab                 # List tabs\nagent-browser tab new [url]       # New tab\nagent-browser tab 2               # Switch to tab by index\nagent-browser tab close           # Close current tab\nagent-browser tab close 2         # Close tab by index\nagent-browser window new          # New window\n```\n\n## Frames\n\n```bash\nagent-browser frame \"#iframe\"     # Switch to iframe\nagent-browser frame main          # Back to main frame\n```\n\n## Dialogs\n\n```bash\nagent-browser dialog accept [text]  # Accept dialog\nagent-browser dialog dismiss        # Dismiss dialog\n```\n\n## JavaScript\n\n```bash\nagent-browser eval \"document.title\"          # Simple expressions only\nagent-browser eval -b \"<base64>\"             # Any JavaScript (base64 encoded)\nagent-browser eval --stdin                   # Read script from stdin\n```\n\nUse `-b`/`--base64` or `--stdin` for reliable execution. Shell escaping with nested quotes and special characters is error-prone.\n\n```bash\n# Base64 encode your script, then:\nagent-browser eval -b \"ZG9jdW1lbnQucXVlcnlTZWxlY3RvcignW3NyYyo9Il9uZXh0Il0nKQ==\"\n\n# Or use stdin with heredoc for multiline scripts:\ncat <<'EOF' | agent-browser eval --stdin\nconst links = document.querySelectorAll('a');\nArray.from(links).map(a => a.href);\nEOF\n```\n\n## State Management\n\n```bash\nagent-browser state save auth.json    # Save cookies, storage, auth state\nagent-browser state load auth.json    # Restore saved state\n```\n\n## Global Options\n\n```bash\nagent-browser --session <name> ...    # Isolated browser session\nagent-browser --json ...              # JSON output for parsing\nagent-browser --headed ...            # Show browser window (not headless)\nagent-browser --full ...              # Full page screenshot (-f)\nagent-browser --cdp <port> ...        # Connect via Chrome DevTools Protocol\nagent-browser -p <provider> ...       # Cloud browser provider (--provider)\nagent-browser --proxy <url> ...       # Use proxy server\nagent-browser --proxy-bypass <hosts>  # Hosts to bypass proxy\nagent-browser --headers <json> ...    # HTTP headers scoped to URL's origin\nagent-browser --executable-path <p>   # Custom browser executable\nagent-browser --extension <path> ...  # Load browser extension (repeatable)\nagent-browser --ignore-https-errors   # Ignore SSL certificate errors\nagent-browser --help                  # Show help (-h)\nagent-browser --version               # Show version (-V)\nagent-browser <command> --help        # Show detailed help for a command\n```\n\n## Debugging\n\n```bash\nagent-browser --headed open example.com   # Show browser window\nagent-browser --cdp 9222 snapshot         # Connect via CDP port\nagent-browser connect 9222                # Alternative: connect command\nagent-browser console                     # View console messages\nagent-browser console --clear             # Clear console\nagent-browser errors                      # View page errors\nagent-browser errors --clear              # Clear errors\nagent-browser highlight @e1               # Highlight element\nagent-browser trace start                 # Start recording trace\nagent-browser trace stop trace.zip        # Stop and save trace\nagent-browser profiler start              # Start Chrome DevTools profiling\nagent-browser profiler stop trace.json    # Stop and save profile\n```\n\n## Environment Variables\n\n```bash\nAGENT_BROWSER_SESSION=\"mysession\"            # Default session name\nAGENT_BROWSER_EXECUTABLE_PATH=\"/path/chrome\" # Custom browser path\nAGENT_BROWSER_EXTENSIONS=\"/ext1,/ext2\"       # Comma-separated extension paths\nAGENT_BROWSER_PROVIDER=\"browserbase\"         # Cloud browser provider\nAGENT_BROWSER_STREAM_PORT=\"9223\"             # WebSocket streaming port\nAGENT_BROWSER_HOME=\"/path/to/agent-browser\"  # Custom install location\n```\n","src/resources/skills/agent-browser/references/profiling.md":"# Profiling\n\nCapture Chrome DevTools performance profiles during browser automation for performance analysis.\n\n**Related**: [commands.md](commands.md) for full command reference, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Profiling](#basic-profiling)\n- [Profiler Commands](#profiler-commands)\n- [Categories](#categories)\n- [Use Cases](#use-cases)\n- [Output Format](#output-format)\n- [Viewing Profiles](#viewing-profiles)\n- [Limitations](#limitations)\n\n## Basic Profiling\n\n```bash\n# Start profiling\nagent-browser profiler start\n\n# Perform actions\nagent-browser navigate https://example.com\nagent-browser click \"#button\"\nagent-browser wait 1000\n\n# Stop and save\nagent-browser profiler stop ./trace.json\n```\n\n## Profiler Commands\n\n```bash\n# Start profiling with default categories\nagent-browser profiler start\n\n# Start with custom trace categories\nagent-browser profiler start --categories \"devtools.timeline,v8.execute,blink.user_timing\"\n\n# Stop profiling and save to file\nagent-browser profiler stop ./trace.json\n```\n\n## Categories\n\nThe `--categories` flag accepts a comma-separated list of Chrome trace categories. Default categories include:\n\n- `devtools.timeline` -- standard DevTools performance traces\n- `v8.execute` -- time spent running JavaScript\n- `blink` -- renderer events\n- `blink.user_timing` -- `performance.mark()` / `performance.measure()` calls\n- `latencyInfo` -- input-to-latency tracking\n- `renderer.scheduler` -- task scheduling and execution\n- `toplevel` -- broad-spectrum basic events\n\nSeveral `disabled-by-default-*` categories are also included for detailed timeline, call stack, and V8 CPU profiling data.\n\n## Use Cases\n\n### Diagnosing Slow Page Loads\n\n```bash\nagent-browser profiler start\nagent-browser navigate https://app.example.com\nagent-browser wait --load networkidle\nagent-browser profiler stop ./page-load-profile.json\n```\n\n### Profiling User Interactions\n\n```bash\nagent-browser navigate https://app.example.com\nagent-browser profiler start\nagent-browser click \"#submit\"\nagent-browser wait 2000\nagent-browser profiler stop ./interaction-profile.json\n```\n\n### CI Performance Regression Checks\n\n```bash\n#!/bin/bash\nagent-browser profiler start\nagent-browser navigate https://app.example.com\nagent-browser wait --load networkidle\nagent-browser profiler stop \"./profiles/build-${BUILD_ID}.json\"\n```\n\n## Output Format\n\nThe output is a JSON file in Chrome Trace Event format:\n\n```json\n{\n  \"traceEvents\": [\n    { \"cat\": \"devtools.timeline\", \"name\": \"RunTask\", \"ph\": \"X\", \"ts\": 12345, \"dur\": 100, ... },\n    ...\n  ],\n  \"metadata\": {\n    \"clock-domain\": \"LINUX_CLOCK_MONOTONIC\"\n  }\n}\n```\n\nThe `metadata.clock-domain` field is set based on the host platform (Linux or macOS). On Windows it is omitted.\n\n## Viewing Profiles\n\nLoad the output JSON file in any of these tools:\n\n- **Chrome DevTools**: Performance panel > Load profile (Ctrl+Shift+I > Performance)\n- **Perfetto UI**: https://ui.perfetto.dev/ -- drag and drop the JSON file\n- **Trace Viewer**: `chrome://tracing` in any Chromium browser\n\n## Limitations\n\n- Only works with Chromium-based browsers (Chrome, Edge). Not supported on Firefox or WebKit.\n- Trace data accumulates in memory while profiling is active (capped at 5 million events). Stop profiling promptly after the area of interest.\n- Data collection on stop has a 30-second timeout. If the browser is unresponsive, the stop command may fail.\n","src/resources/skills/agent-browser/references/proxy-support.md":"# Proxy Support\n\nProxy configuration for geo-testing, rate limiting avoidance, and corporate environments.\n\n**Related**: [commands.md](commands.md) for global options, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Proxy Configuration](#basic-proxy-configuration)\n- [Authenticated Proxy](#authenticated-proxy)\n- [SOCKS Proxy](#socks-proxy)\n- [Proxy Bypass](#proxy-bypass)\n- [Common Use Cases](#common-use-cases)\n- [Verifying Proxy Connection](#verifying-proxy-connection)\n- [Troubleshooting](#troubleshooting)\n- [Best Practices](#best-practices)\n\n## Basic Proxy Configuration\n\nUse the `--proxy` flag or set proxy via environment variable:\n\n```bash\n# Via CLI flag\nagent-browser --proxy \"http://proxy.example.com:8080\" open https://example.com\n\n# Via environment variable\nexport HTTP_PROXY=\"http://proxy.example.com:8080\"\nagent-browser open https://example.com\n\n# HTTPS proxy\nexport HTTPS_PROXY=\"https://proxy.example.com:8080\"\nagent-browser open https://example.com\n\n# Both\nexport HTTP_PROXY=\"http://proxy.example.com:8080\"\nexport HTTPS_PROXY=\"http://proxy.example.com:8080\"\nagent-browser open https://example.com\n```\n\n## Authenticated Proxy\n\nFor proxies requiring authentication:\n\n```bash\n# Include credentials in URL\nexport HTTP_PROXY=\"http://username:password@proxy.example.com:8080\"\nagent-browser open https://example.com\n```\n\n## SOCKS Proxy\n\n```bash\n# SOCKS5 proxy\nexport ALL_PROXY=\"socks5://proxy.example.com:1080\"\nagent-browser open https://example.com\n\n# SOCKS5 with auth\nexport ALL_PROXY=\"socks5://user:pass@proxy.example.com:1080\"\nagent-browser open https://example.com\n```\n\n## Proxy Bypass\n\nSkip proxy for specific domains using `--proxy-bypass` or `NO_PROXY`:\n\n```bash\n# Via CLI flag\nagent-browser --proxy \"http://proxy.example.com:8080\" --proxy-bypass \"localhost,*.internal.com\" open https://example.com\n\n# Via environment variable\nexport NO_PROXY=\"localhost,127.0.0.1,.internal.company.com\"\nagent-browser open https://internal.company.com  # Direct connection\nagent-browser open https://external.com          # Via proxy\n```\n\n## Common Use Cases\n\n### Geo-Location Testing\n\n```bash\n#!/bin/bash\n# Test site from different regions using geo-located proxies\n\nPROXIES=(\n    \"http://us-proxy.example.com:8080\"\n    \"http://eu-proxy.example.com:8080\"\n    \"http://asia-proxy.example.com:8080\"\n)\n\nfor proxy in \"${PROXIES[@]}\"; do\n    export HTTP_PROXY=\"$proxy\"\n    export HTTPS_PROXY=\"$proxy\"\n\n    region=$(echo \"$proxy\" | grep -oP '^\\w+-\\w+')\n    echo \"Testing from: $region\"\n\n    agent-browser --session \"$region\" open https://example.com\n    agent-browser --session \"$region\" screenshot \"./screenshots/$region.png\"\n    agent-browser --session \"$region\" close\ndone\n```\n\n### Rotating Proxies for Scraping\n\n```bash\n#!/bin/bash\n# Rotate through proxy list to avoid rate limiting\n\nPROXY_LIST=(\n    \"http://proxy1.example.com:8080\"\n    \"http://proxy2.example.com:8080\"\n    \"http://proxy3.example.com:8080\"\n)\n\nURLS=(\n    \"https://site.com/page1\"\n    \"https://site.com/page2\"\n    \"https://site.com/page3\"\n)\n\nfor i in \"${!URLS[@]}\"; do\n    proxy_index=$((i % ${#PROXY_LIST[@]}))\n    export HTTP_PROXY=\"${PROXY_LIST[$proxy_index]}\"\n    export HTTPS_PROXY=\"${PROXY_LIST[$proxy_index]}\"\n\n    agent-browser open \"${URLS[$i]}\"\n    agent-browser get text body > \"output-$i.txt\"\n    agent-browser close\n\n    sleep 1  # Polite delay\ndone\n```\n\n### Corporate Network Access\n\n```bash\n#!/bin/bash\n# Access internal sites via corporate proxy\n\nexport HTTP_PROXY=\"http://corpproxy.company.com:8080\"\nexport HTTPS_PROXY=\"http://corpproxy.company.com:8080\"\nexport NO_PROXY=\"localhost,127.0.0.1,.company.com\"\n\n# External sites go through proxy\nagent-browser open https://external-vendor.com\n\n# Internal sites bypass proxy\nagent-browser open https://intranet.company.com\n```\n\n## Verifying Proxy Connection\n\n```bash\n# Check your apparent IP\nagent-browser open https://httpbin.org/ip\nagent-browser get text body\n# Should show proxy's IP, not your real IP\n```\n\n## Troubleshooting\n\n### Proxy Connection Failed\n\n```bash\n# Test proxy connectivity first\ncurl -x http://proxy.example.com:8080 https://httpbin.org/ip\n\n# Check if proxy requires auth\nexport HTTP_PROXY=\"http://user:pass@proxy.example.com:8080\"\n```\n\n### SSL/TLS Errors Through Proxy\n\nSome proxies perform SSL inspection. If you encounter certificate errors:\n\n```bash\n# For testing only - not recommended for production\nagent-browser open https://example.com --ignore-https-errors\n```\n\n### Slow Performance\n\n```bash\n# Use proxy only when necessary\nexport NO_PROXY=\"*.cdn.com,*.static.com\"  # Direct CDN access\n```\n\n## Best Practices\n\n1. **Use environment variables** - Don't hardcode proxy credentials\n2. **Set NO_PROXY appropriately** - Avoid routing local traffic through proxy\n3. **Test proxy before automation** - Verify connectivity with simple requests\n4. **Handle proxy failures gracefully** - Implement retry logic for unstable proxies\n5. **Rotate proxies for large scraping jobs** - Distribute load and avoid bans\n","src/resources/skills/agent-browser/references/session-management.md":"# Session Management\n\nMultiple isolated browser sessions with state persistence and concurrent browsing.\n\n**Related**: [authentication.md](authentication.md) for login patterns, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Named Sessions](#named-sessions)\n- [Session Isolation Properties](#session-isolation-properties)\n- [Session State Persistence](#session-state-persistence)\n- [Common Patterns](#common-patterns)\n- [Default Session](#default-session)\n- [Session Cleanup](#session-cleanup)\n- [Best Practices](#best-practices)\n\n## Named Sessions\n\nUse `--session` flag to isolate browser contexts:\n\n```bash\n# Session 1: Authentication flow\nagent-browser --session auth open https://app.example.com/login\n\n# Session 2: Public browsing (separate cookies, storage)\nagent-browser --session public open https://example.com\n\n# Commands are isolated by session\nagent-browser --session auth fill @e1 \"user@example.com\"\nagent-browser --session public get text body\n```\n\n## Session Isolation Properties\n\nEach session has independent:\n- Cookies\n- LocalStorage / SessionStorage\n- IndexedDB\n- Cache\n- Browsing history\n- Open tabs\n\n## Session State Persistence\n\n### Save Session State\n\n```bash\n# Save cookies, storage, and auth state\nagent-browser state save /path/to/auth-state.json\n```\n\n### Load Session State\n\n```bash\n# Restore saved state\nagent-browser state load /path/to/auth-state.json\n\n# Continue with authenticated session\nagent-browser open https://app.example.com/dashboard\n```\n\n### State File Contents\n\n```json\n{\n  \"cookies\": [...],\n  \"localStorage\": {...},\n  \"sessionStorage\": {...},\n  \"origins\": [...]\n}\n```\n\n## Common Patterns\n\n### Authenticated Session Reuse\n\n```bash\n#!/bin/bash\n# Save login state once, reuse many times\n\nSTATE_FILE=\"/tmp/auth-state.json\"\n\n# Check if we have saved state\nif [[ -f \"$STATE_FILE\" ]]; then\n    agent-browser state load \"$STATE_FILE\"\n    agent-browser open https://app.example.com/dashboard\nelse\n    # Perform login\n    agent-browser open https://app.example.com/login\n    agent-browser snapshot -i\n    agent-browser fill @e1 \"$USERNAME\"\n    agent-browser fill @e2 \"$PASSWORD\"\n    agent-browser click @e3\n    agent-browser wait --load networkidle\n\n    # Save for future use\n    agent-browser state save \"$STATE_FILE\"\nfi\n```\n\n### Concurrent Scraping\n\n```bash\n#!/bin/bash\n# Scrape multiple sites concurrently\n\n# Start all sessions\nagent-browser --session site1 open https://site1.com &\nagent-browser --session site2 open https://site2.com &\nagent-browser --session site3 open https://site3.com &\nwait\n\n# Extract from each\nagent-browser --session site1 get text body > site1.txt\nagent-browser --session site2 get text body > site2.txt\nagent-browser --session site3 get text body > site3.txt\n\n# Cleanup\nagent-browser --session site1 close\nagent-browser --session site2 close\nagent-browser --session site3 close\n```\n\n### A/B Testing Sessions\n\n```bash\n# Test different user experiences\nagent-browser --session variant-a open \"https://app.com?variant=a\"\nagent-browser --session variant-b open \"https://app.com?variant=b\"\n\n# Compare\nagent-browser --session variant-a screenshot /tmp/variant-a.png\nagent-browser --session variant-b screenshot /tmp/variant-b.png\n```\n\n## Default Session\n\nWhen `--session` is omitted, commands use the default session:\n\n```bash\n# These use the same default session\nagent-browser open https://example.com\nagent-browser snapshot -i\nagent-browser close  # Closes default session\n```\n\n## Session Cleanup\n\n```bash\n# Close specific session\nagent-browser --session auth close\n\n# List active sessions\nagent-browser session list\n```\n\n## Best Practices\n\n### 1. Name Sessions Semantically\n\n```bash\n# GOOD: Clear purpose\nagent-browser --session github-auth open https://github.com\nagent-browser --session docs-scrape open https://docs.example.com\n\n# AVOID: Generic names\nagent-browser --session s1 open https://github.com\n```\n\n### 2. Always Clean Up\n\n```bash\n# Close sessions when done\nagent-browser --session auth close\nagent-browser --session scrape close\n```\n\n### 3. Handle State Files Securely\n\n```bash\n# Don't commit state files (contain auth tokens!)\necho \"*.auth-state.json\" >> .gitignore\n\n# Delete after use\nrm /tmp/auth-state.json\n```\n\n### 4. Timeout Long Sessions\n\n```bash\n# Set timeout for automated scripts\ntimeout 60 agent-browser --session long-task get text body\n```\n","src/resources/skills/agent-browser/references/snapshot-refs.md":"# Snapshot and Refs\n\nCompact element references that reduce context usage dramatically for AI agents.\n\n**Related**: [commands.md](commands.md) for full command reference, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [How Refs Work](#how-refs-work)\n- [Snapshot Command](#the-snapshot-command)\n- [Using Refs](#using-refs)\n- [Ref Lifecycle](#ref-lifecycle)\n- [Best Practices](#best-practices)\n- [Ref Notation Details](#ref-notation-details)\n- [Troubleshooting](#troubleshooting)\n\n## How Refs Work\n\nTraditional approach:\n```\nFull DOM/HTML → AI parses → CSS selector → Action (~3000-5000 tokens)\n```\n\nagent-browser approach:\n```\nCompact snapshot → @refs assigned → Direct interaction (~200-400 tokens)\n```\n\n## The Snapshot Command\n\n```bash\n# Basic snapshot (shows page structure)\nagent-browser snapshot\n\n# Interactive snapshot (-i flag) - RECOMMENDED\nagent-browser snapshot -i\n```\n\n### Snapshot Output Format\n\n```\nPage: Example Site - Home\nURL: https://example.com\n\n@e1 [header]\n  @e2 [nav]\n    @e3 [a] \"Home\"\n    @e4 [a] \"Products\"\n    @e5 [a] \"About\"\n  @e6 [button] \"Sign In\"\n\n@e7 [main]\n  @e8 [h1] \"Welcome\"\n  @e9 [form]\n    @e10 [input type=\"email\"] placeholder=\"Email\"\n    @e11 [input type=\"password\"] placeholder=\"Password\"\n    @e12 [button type=\"submit\"] \"Log In\"\n\n@e13 [footer]\n  @e14 [a] \"Privacy Policy\"\n```\n\n## Using Refs\n\nOnce you have refs, interact directly:\n\n```bash\n# Click the \"Sign In\" button\nagent-browser click @e6\n\n# Fill email input\nagent-browser fill @e10 \"user@example.com\"\n\n# Fill password\nagent-browser fill @e11 \"password123\"\n\n# Submit the form\nagent-browser click @e12\n```\n\n## Ref Lifecycle\n\n**IMPORTANT**: Refs are invalidated when the page changes!\n\n```bash\n# Get initial snapshot\nagent-browser snapshot -i\n# @e1 [button] \"Next\"\n\n# Click triggers page change\nagent-browser click @e1\n\n# MUST re-snapshot to get new refs!\nagent-browser snapshot -i\n# @e1 [h1] \"Page 2\"  ← Different element now!\n```\n\n## Best Practices\n\n### 1. Always Snapshot Before Interacting\n\n```bash\n# CORRECT\nagent-browser open https://example.com\nagent-browser snapshot -i          # Get refs first\nagent-browser click @e1            # Use ref\n\n# WRONG\nagent-browser open https://example.com\nagent-browser click @e1            # Ref doesn't exist yet!\n```\n\n### 2. Re-Snapshot After Navigation\n\n```bash\nagent-browser click @e5            # Navigates to new page\nagent-browser snapshot -i          # Get new refs\nagent-browser click @e1            # Use new refs\n```\n\n### 3. Re-Snapshot After Dynamic Changes\n\n```bash\nagent-browser click @e1            # Opens dropdown\nagent-browser snapshot -i          # See dropdown items\nagent-browser click @e7            # Select item\n```\n\n### 4. Snapshot Specific Regions\n\nFor complex pages, snapshot specific areas:\n\n```bash\n# Snapshot just the form\nagent-browser snapshot @e9\n```\n\n## Ref Notation Details\n\n```\n@e1 [tag type=\"value\"] \"text content\" placeholder=\"hint\"\n│    │   │             │               │\n│    │   │             │               └─ Additional attributes\n│    │   │             └─ Visible text\n│    │   └─ Key attributes shown\n│    └─ HTML tag name\n└─ Unique ref ID\n```\n\n### Common Patterns\n\n```\n@e1 [button] \"Submit\"                    # Button with text\n@e2 [input type=\"email\"]                 # Email input\n@e3 [input type=\"password\"]              # Password input\n@e4 [a href=\"/page\"] \"Link Text\"         # Anchor link\n@e5 [select]                             # Dropdown\n@e6 [textarea] placeholder=\"Message\"     # Text area\n@e7 [div class=\"modal\"]                  # Container (when relevant)\n@e8 [img alt=\"Logo\"]                     # Image\n@e9 [checkbox] checked                   # Checked checkbox\n@e10 [radio] selected                    # Selected radio\n```\n\n## Troubleshooting\n\n### \"Ref not found\" Error\n\n```bash\n# Ref may have changed - re-snapshot\nagent-browser snapshot -i\n```\n\n### Element Not Visible in Snapshot\n\n```bash\n# Scroll down to reveal element\nagent-browser scroll down 1000\nagent-browser snapshot -i\n\n# Or wait for dynamic content\nagent-browser wait 1000\nagent-browser snapshot -i\n```\n\n### Too Many Elements\n\n```bash\n# Snapshot specific container\nagent-browser snapshot @e5\n\n# Or use get text for content-only extraction\nagent-browser get text @e5\n```\n","src/resources/skills/agent-browser/references/video-recording.md":"# Video Recording\n\nCapture browser automation as video for debugging, documentation, or verification.\n\n**Related**: [commands.md](commands.md) for full command reference, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Recording](#basic-recording)\n- [Recording Commands](#recording-commands)\n- [Use Cases](#use-cases)\n- [Best Practices](#best-practices)\n- [Output Format](#output-format)\n- [Limitations](#limitations)\n\n## Basic Recording\n\n```bash\n# Start recording\nagent-browser record start ./demo.webm\n\n# Perform actions\nagent-browser open https://example.com\nagent-browser snapshot -i\nagent-browser click @e1\nagent-browser fill @e2 \"test input\"\n\n# Stop and save\nagent-browser record stop\n```\n\n## Recording Commands\n\n```bash\n# Start recording to file\nagent-browser record start ./output.webm\n\n# Stop current recording\nagent-browser record stop\n\n# Restart with new file (stops current + starts new)\nagent-browser record restart ./take2.webm\n```\n\n## Use Cases\n\n### Debugging Failed Automation\n\n```bash\n#!/bin/bash\n# Record automation for debugging\n\nagent-browser record start ./debug-$(date +%Y%m%d-%H%M%S).webm\n\n# Run your automation\nagent-browser open https://app.example.com\nagent-browser snapshot -i\nagent-browser click @e1 || {\n    echo \"Click failed - check recording\"\n    agent-browser record stop\n    exit 1\n}\n\nagent-browser record stop\n```\n\n### Documentation Generation\n\n```bash\n#!/bin/bash\n# Record workflow for documentation\n\nagent-browser record start ./docs/how-to-login.webm\n\nagent-browser open https://app.example.com/login\nagent-browser wait 1000  # Pause for visibility\n\nagent-browser snapshot -i\nagent-browser fill @e1 \"demo@example.com\"\nagent-browser wait 500\n\nagent-browser fill @e2 \"password\"\nagent-browser wait 500\n\nagent-browser click @e3\nagent-browser wait --load networkidle\nagent-browser wait 1000  # Show result\n\nagent-browser record stop\n```\n\n### CI/CD Test Evidence\n\n```bash\n#!/bin/bash\n# Record E2E test runs for CI artifacts\n\nTEST_NAME=\"${1:-e2e-test}\"\nRECORDING_DIR=\"./test-recordings\"\nmkdir -p \"$RECORDING_DIR\"\n\nagent-browser record start \"$RECORDING_DIR/$TEST_NAME-$(date +%s).webm\"\n\n# Run test\nif run_e2e_test; then\n    echo \"Test passed\"\nelse\n    echo \"Test failed - recording saved\"\nfi\n\nagent-browser record stop\n```\n\n## Best Practices\n\n### 1. Add Pauses for Clarity\n\n```bash\n# Slow down for human viewing\nagent-browser click @e1\nagent-browser wait 500  # Let viewer see result\n```\n\n### 2. Use Descriptive Filenames\n\n```bash\n# Include context in filename\nagent-browser record start ./recordings/login-flow-2024-01-15.webm\nagent-browser record start ./recordings/checkout-test-run-42.webm\n```\n\n### 3. Handle Recording in Error Cases\n\n```bash\n#!/bin/bash\nset -e\n\ncleanup() {\n    agent-browser record stop 2>/dev/null || true\n    agent-browser close 2>/dev/null || true\n}\ntrap cleanup EXIT\n\nagent-browser record start ./automation.webm\n# ... automation steps ...\n```\n\n### 4. Combine with Screenshots\n\n```bash\n# Record video AND capture key frames\nagent-browser record start ./flow.webm\n\nagent-browser open https://example.com\nagent-browser screenshot ./screenshots/step1-homepage.png\n\nagent-browser click @e1\nagent-browser screenshot ./screenshots/step2-after-click.png\n\nagent-browser record stop\n```\n\n## Output Format\n\n- Default format: WebM (VP8/VP9 codec)\n- Compatible with all modern browsers and video players\n- Compressed but high quality\n\n## Limitations\n\n- Recording adds slight overhead to automation\n- Large recordings can consume significant disk space\n- Some headless environments may have codec limitations\n","src/resources/skills/api-design/SKILL.md":"---\nname: api-design\ndescription: Design or review an HTTP/REST/GraphQL API for versioning, pagination, error shapes, idempotency, auth, and evolvability. Use when asked to \"design an API\", \"shape the endpoints\", \"design the schema\", \"add a new endpoint\", \"review this API\", or when building/modifying a public or internal HTTP surface. Complements `design-an-interface` (which is interface-agnostic) by covering HTTP-specific concerns like status codes, cache headers, and breaking-change management.\n---\n\n<objective>\nShape an HTTP or GraphQL API so callers get predictable, evolvable, and honest semantics. The deliverable is a concrete endpoint/schema sketch with: URL or operation names, method/verb, request shape, response shape, error shape, auth model, pagination strategy, and versioning stance. Optimize for \"clients that exist in 2 years\" over \"client that's easy to write today\".\n</objective>\n\n<context>\nGSD-2 has `design-an-interface` for general module-interface design; this skill is the HTTP/GraphQL specialization. REST and GraphQL carry baggage — status codes, verbs, nullability, pagination — that a generic interface-design discussion glosses over.\n\nInvocation points:\n- Adding a new public API endpoint\n- Redesigning an internal API boundary between services\n- Code review of a PR that introduces HTTP handlers\n- A slice whose acceptance criteria include \"the API works\"\n- A GraphQL schema change\n</context>\n\n<core_principle>\n**CALLERS OUTLIVE YOUR ASSUMPTIONS.** An API you ship today has to keep working when your internals change, when the mobile app version two is still in use, and when a third party integrates against it. Design for extension, not just for the current caller.\n\n**HONEST STATUS CODES.** 200 OK with `{\"error\": \"not found\"}` is a lie. 404 says not found. Use the HTTP semantics the protocol offers — HTTP clients, caches, and intermediaries rely on them.\n\n**PAGINATION IS NON-OPTIONAL.** Any list endpoint that doesn't paginate will eventually get a request for \"all records\" that kills your database.\n</core_principle>\n\n<process>\n\n## Step 1: Gather the contract\n\nAnswer, or ask (one round, 1–3 questions):\n\n1. **Who are the callers?** Internal service / mobile app / public third-party / same-repo frontend.\n2. **What's the versioning stance?** None / URL-path (`/v1/`) / header-based / GraphQL schema evolution.\n3. **Auth model?** Public / API key / OAuth / session cookie / mTLS / none-but-internal-only.\n4. **Idempotency expectation?** Is a retry safe? Required?\n5. **Consistency model?** Read-your-writes, eventual, serializable?\n\n## Step 2: Resource and operation naming\n\n### REST\n\n- Nouns not verbs in URLs: `POST /users`, not `POST /createUser`.\n- Plural resources: `/users/42`, not `/user/42`.\n- Nested only when the relationship is hierarchical and the child has no independent identity: `/users/42/sessions/3`. Otherwise flat: `/sessions/3?userId=42`.\n- Use subresources for actions that don't fit CRUD: `POST /users/42:deactivate` (colon syntax) or `POST /users/42/actions/deactivate`.\n\n### GraphQL\n\n- Queries are nouns; mutations are verbs: `user(id)`, `createUser(input)`, `deactivateUser(id)`.\n- Group related mutations under an input type: `createUser(input: CreateUserInput!)`.\n- Return the affected object plus any derived/computed fields from mutations — lets clients avoid a refetch.\n\n## Step 3: Methods and status codes\n\n### REST\n\n| Method | Intent | Idempotent? | Default success |\n|---|---|---|---|\n| GET | Read | Yes | 200, or 304 if conditional |\n| POST | Create or non-idempotent action | No | 201 with `Location` on create, 200 on action |\n| PUT | Replace (full-object) | Yes | 200 with body, or 204 |\n| PATCH | Partial update | No (usually) | 200 with body |\n| DELETE | Remove | Yes | 204 |\n\nErrors:\n- 400: caller screwed up the request shape\n- 401: no/invalid auth\n- 403: authed but not allowed\n- 404: resource doesn't exist\n- 409: conflict (version mismatch, unique constraint)\n- 410: gone (vs 404 when the resource previously existed and you want to signal that)\n- 422: validation failed\n- 429: rate-limited — include `Retry-After`\n- 500: genuinely unexpected server error\n- 503: service down or overloaded — include `Retry-After`\n\nNever 200-with-error-body. Never 500 for a 4xx cause.\n\n### GraphQL\n\n- Top-level errors (`errors[]`) for transport-level failures. Domain errors (validation, not-found, forbidden) go in the typed return — use a union or result type.\n- Partial results are expected; design the schema so `null` on a field is meaningful, not a signal of generic failure.\n\n## Step 4: Pagination\n\n- **Cursor-based by default.** Opaque cursor string, `limit`, return `nextCursor` when more exists. Scales, stable under writes.\n- **Offset-based only when:** dataset is small, user needs jump-to-page semantics (admin tables), and you're willing to accept stability drift.\n- **Never \"return everything\"** as default. Put a hard upper bound on `limit` (e.g., 200).\n- GraphQL: use Relay-style connections (`edges`, `pageInfo`) if the ecosystem expects it; otherwise a simpler `{items, nextCursor}` is fine.\n\n## Step 5: Error shape\n\nStandardize one shape and use it everywhere. Example REST:\n\n```json\n{\n  \"error\": {\n    \"code\": \"user_not_found\",\n    \"message\": \"No user with id 42\",\n    \"details\": { \"userId\": 42 },\n    \"requestId\": \"req_abc123\"\n  }\n}\n```\n\n- `code` is machine-readable; stable; documented.\n- `message` is human-readable; can change.\n- `details` carries structured context.\n- `requestId` lets callers report bugs.\n\nErrors don't leak stack traces, file paths, or internal queries.\n\n## Step 6: Idempotency, caching, concurrency\n\n- **Idempotency keys** for POST operations that mustn't double-execute on retry. Caller passes `Idempotency-Key: <uuid>`; server dedupes for a window.\n- **ETags** for GET + conditional updates (`If-Match` on PUT/PATCH).\n- **Cache-Control** on GETs that are safely cacheable.\n- **Optimistic concurrency:** when multiple writers collide, 409 with the current state. Don't silently clobber.\n\n## Step 7: Versioning and evolution\n\n- **Additive changes are free:** new optional fields, new endpoints, new optional query params.\n- **Breaking changes need a plan:** path-versioned (`/v2/`), sunset headers on `/v1/`, deprecation window communicated. Or, for GraphQL, `@deprecated` on fields with a migration note.\n- **Document the contract:** OpenAPI/GraphQL SDL. Keep it in the repo. Make it part of the PR that introduces the change.\n\n## Step 8: Review or write it up\n\nIf this is a review, produce findings in the same shape as `security-review` / `review` — file:line, category, recommendation.\n\nIf this is a new design, produce:\n\n```markdown\n## <API name>\n\n### Scope\n<what the API is for, who calls it>\n\n### Endpoints / Operations\n- `POST /users` — create user. Request: `{email, name}`. Response 201: `{id, email, name, createdAt}` + `Location: /users/<id>`. Errors: 409 email taken, 422 invalid.\n- ...\n\n### Auth\n<model + where to put the credential>\n\n### Pagination\n<cursor shape, max limit>\n\n### Error shape\n<one canonical shape>\n\n### Idempotency / concurrency\n<rules>\n\n### Versioning\n<stance + how breaking changes will be handled>\n\n### OpenAPI / SDL\n<link or inline>\n```\n\nAppend architectural decisions to `.gsd/DECISIONS.md`.\n\n</process>\n\n<anti_patterns>\n\n- **200 OK with `{\"error\": \"...\"}`.** Lies to caches, proxies, retry libraries.\n- **Unbounded list endpoints.** `GET /users` without a `limit` cap will bite you.\n- **Offset pagination at scale.** Drifts under writes; slow at high offsets.\n- **Free-form error messages with no code.** Machine callers can't branch on prose.\n- **Breaking changes in-place.** Callers break; versioning exists for a reason.\n- **Ignoring idempotency on retriable POSTs.** Double-charges, duplicate records.\n- **Auth checks at the handler only, not the service layer.** Defense in depth.\n\n</anti_patterns>\n\n<success_criteria>\n\n- [ ] Every endpoint/operation has named request, response, and error shapes.\n- [ ] Status codes match HTTP semantics — no 200-with-error.\n- [ ] List endpoints paginate; max limit is documented.\n- [ ] A single error shape is used everywhere, with a machine-readable code.\n- [ ] Versioning stance is stated — even if the answer is \"additive only for now.\"\n- [ ] OpenAPI/SDL reflects the design and lives in the repo.\n- [ ] Decisions appear in `.gsd/DECISIONS.md`.\n\n</success_criteria>\n","src/resources/skills/best-practices/SKILL.md":"---\nname: best-practices\ndescription: Apply modern web development best practices for security, compatibility, and code quality. Use when asked to \"apply best practices\", \"security audit\", \"modernize code\", \"code quality review\", or \"check for vulnerabilities\".\nlicense: MIT\nmetadata:\n  author: web-quality-skills\n  version: \"1.0\"\n---\n\n# Best practices\n\nModern web development standards based on Lighthouse best practices audits. Covers security, browser compatibility, and code quality patterns.\n\n## Security\n\n### HTTPS everywhere\n\n**Enforce HTTPS:**\n```html\n<!-- ❌ Mixed content -->\n<img src=\"http://example.com/image.jpg\">\n<script src=\"http://cdn.example.com/script.js\"></script>\n\n<!-- ✅ HTTPS only -->\n<img src=\"https://example.com/image.jpg\">\n<script src=\"https://cdn.example.com/script.js\"></script>\n\n<!-- ✅ Protocol-relative (will use page's protocol) -->\n<img src=\"//example.com/image.jpg\">\n```\n\n**HSTS Header:**\n```\nStrict-Transport-Security: max-age=31536000; includeSubDomains; preload\n```\n\n### Content Security Policy (CSP)\n\n```html\n<!-- Basic CSP via meta tag -->\n<meta http-equiv=\"Content-Security-Policy\" \n      content=\"default-src 'self'; \n               script-src 'self' https://trusted-cdn.com; \n               style-src 'self' 'unsafe-inline';\n               img-src 'self' data: https:;\n               connect-src 'self' https://api.example.com;\">\n\n<!-- Better: HTTP header -->\n```\n\n**CSP Header (recommended):**\n```\nContent-Security-Policy: \n  default-src 'self';\n  script-src 'self' 'nonce-abc123' https://trusted.com;\n  style-src 'self' 'nonce-abc123';\n  img-src 'self' data: https:;\n  connect-src 'self' https://api.example.com;\n  frame-ancestors 'self';\n  base-uri 'self';\n  form-action 'self';\n```\n\n**Using nonces for inline scripts:**\n```html\n<script nonce=\"abc123\">\n  // This inline script is allowed\n</script>\n```\n\n### Security headers\n\n```\n# Prevent clickjacking\nX-Frame-Options: DENY\n\n# Prevent MIME type sniffing\nX-Content-Type-Options: nosniff\n\n# Enable XSS filter (legacy browsers)\nX-XSS-Protection: 1; mode=block\n\n# Control referrer information\nReferrer-Policy: strict-origin-when-cross-origin\n\n# Permissions policy (formerly Feature-Policy)\nPermissions-Policy: geolocation=(), microphone=(), camera=()\n```\n\n### No vulnerable libraries\n\n```bash\n# Check for vulnerabilities\nnpm audit\nyarn audit\n\n# Auto-fix when possible\nnpm audit fix\n\n# Check specific package\nnpm ls lodash\n```\n\n**Keep dependencies updated:**\n```json\n// package.json\n{\n  \"scripts\": {\n    \"audit\": \"npm audit --audit-level=moderate\",\n    \"update\": \"npm update && npm audit fix\"\n  }\n}\n```\n\n**Known vulnerable patterns to avoid:**\n```javascript\n// ❌ Prototype pollution vulnerable patterns\nObject.assign(target, userInput);\n_.merge(target, userInput);\n\n// ✅ Safer alternatives\nconst safeData = JSON.parse(JSON.stringify(userInput));\n```\n\n### Input sanitization\n\n```javascript\n// ❌ XSS vulnerable\nelement.innerHTML = userInput;\ndocument.write(userInput);\n\n// ✅ Safe text content\nelement.textContent = userInput;\n\n// ✅ If HTML needed, sanitize\nimport DOMPurify from 'dompurify';\nelement.innerHTML = DOMPurify.sanitize(userInput);\n```\n\n### Secure cookies\n\n```javascript\n// ❌ Insecure cookie\ndocument.cookie = \"session=abc123\";\n\n// ✅ Secure cookie (server-side)\nSet-Cookie: session=abc123; Secure; HttpOnly; SameSite=Strict; Path=/\n```\n\n---\n\n## Browser compatibility\n\n### Doctype declaration\n\n```html\n<!-- ❌ Missing or invalid doctype -->\n<HTML>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n\n<!-- ✅ HTML5 doctype -->\n<!DOCTYPE html>\n<html lang=\"en\">\n```\n\n### Character encoding\n\n```html\n<!-- ❌ Missing or late charset -->\n<html>\n<head>\n  <title>Page</title>\n  <meta charset=\"UTF-8\">\n</head>\n\n<!-- ✅ Charset as first element in head -->\n<html>\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Page</title>\n</head>\n```\n\n### Viewport meta tag\n\n```html\n<!-- ❌ Missing viewport -->\n<head>\n  <title>Page</title>\n</head>\n\n<!-- ✅ Responsive viewport -->\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <title>Page</title>\n</head>\n```\n\n### Feature detection\n\n```javascript\n// ❌ Browser detection (brittle)\nif (navigator.userAgent.includes('Chrome')) {\n  // Chrome-specific code\n}\n\n// ✅ Feature detection\nif ('IntersectionObserver' in window) {\n  // Use IntersectionObserver\n} else {\n  // Fallback\n}\n\n// ✅ Using @supports in CSS\n@supports (display: grid) {\n  .container {\n    display: grid;\n  }\n}\n\n@supports not (display: grid) {\n  .container {\n    display: flex;\n  }\n}\n```\n\n### Polyfills (when needed)\n\n```html\n<!-- Load polyfills conditionally -->\n<script>\n  if (!('fetch' in window)) {\n    document.write('<script src=\"/polyfills/fetch.js\"><\\/script>');\n  }\n</script>\n\n<!-- Or use polyfill.io -->\n<script src=\"https://polyfill.io/v3/polyfill.min.js?features=fetch,IntersectionObserver\"></script>\n```\n\n---\n\n## Deprecated APIs\n\n### Avoid these\n\n```javascript\n// ❌ document.write (blocks parsing)\ndocument.write('<script src=\"...\"></script>');\n\n// ✅ Dynamic script loading\nconst script = document.createElement('script');\nscript.src = '...';\ndocument.head.appendChild(script);\n\n// ❌ Synchronous XHR (blocks main thread)\nconst xhr = new XMLHttpRequest();\nxhr.open('GET', url, false); // false = synchronous\n\n// ✅ Async fetch\nconst response = await fetch(url);\n\n// ❌ Application Cache (deprecated)\n<html manifest=\"cache.manifest\">\n\n// ✅ Service Workers\nif ('serviceWorker' in navigator) {\n  navigator.serviceWorker.register('/sw.js');\n}\n```\n\n### Event listener passive\n\n```javascript\n// ❌ Non-passive touch/wheel (may block scrolling)\nelement.addEventListener('touchstart', handler);\nelement.addEventListener('wheel', handler);\n\n// ✅ Passive listeners (allows smooth scrolling)\nelement.addEventListener('touchstart', handler, { passive: true });\nelement.addEventListener('wheel', handler, { passive: true });\n\n// ✅ If you need preventDefault, be explicit\nelement.addEventListener('touchstart', handler, { passive: false });\n```\n\n---\n\n## Console & errors\n\n### No console errors\n\n```javascript\n// ❌ Errors in production\nconsole.log('Debug info'); // Remove in production\nthrow new Error('Unhandled'); // Catch all errors\n\n// ✅ Proper error handling\ntry {\n  riskyOperation();\n} catch (error) {\n  // Log to error tracking service\n  errorTracker.captureException(error);\n  // Show user-friendly message\n  showErrorMessage('Something went wrong. Please try again.');\n}\n```\n\n### Error boundaries (React)\n\n```jsx\nclass ErrorBoundary extends React.Component {\n  state = { hasError: false };\n  \n  static getDerivedStateFromError(error) {\n    return { hasError: true };\n  }\n  \n  componentDidCatch(error, info) {\n    errorTracker.captureException(error, { extra: info });\n  }\n  \n  render() {\n    if (this.state.hasError) {\n      return <FallbackUI />;\n    }\n    return this.props.children;\n  }\n}\n\n// Usage\n<ErrorBoundary>\n  <App />\n</ErrorBoundary>\n```\n\n### Global error handler\n\n```javascript\n// Catch unhandled errors\nwindow.addEventListener('error', (event) => {\n  errorTracker.captureException(event.error);\n});\n\n// Catch unhandled promise rejections\nwindow.addEventListener('unhandledrejection', (event) => {\n  errorTracker.captureException(event.reason);\n});\n```\n\n---\n\n## Source maps\n\n### Production configuration\n\n```javascript\n// ❌ Source maps exposed in production\n// webpack.config.js\nmodule.exports = {\n  devtool: 'source-map', // Exposes source code\n};\n\n// ✅ Hidden source maps (uploaded to error tracker)\nmodule.exports = {\n  devtool: 'hidden-source-map',\n};\n\n// ✅ Or no source maps in production\nmodule.exports = {\n  devtool: process.env.NODE_ENV === 'production' ? false : 'source-map',\n};\n```\n\n---\n\n## Performance best practices\n\n### Avoid blocking patterns\n\n```javascript\n// ❌ Blocking script\n<script src=\"heavy-library.js\"></script>\n\n// ✅ Deferred script\n<script defer src=\"heavy-library.js\"></script>\n\n// ❌ Blocking CSS import\n@import url('other-styles.css');\n\n// ✅ Link tags (parallel loading)\n<link rel=\"stylesheet\" href=\"styles.css\">\n<link rel=\"stylesheet\" href=\"other-styles.css\">\n```\n\n### Efficient event handlers\n\n```javascript\n// ❌ Handler on every element\nitems.forEach(item => {\n  item.addEventListener('click', handleClick);\n});\n\n// ✅ Event delegation\ncontainer.addEventListener('click', (e) => {\n  if (e.target.matches('.item')) {\n    handleClick(e);\n  }\n});\n```\n\n### Memory management\n\n```javascript\n// ❌ Memory leak (never removed)\nconst handler = () => { /* ... */ };\nwindow.addEventListener('resize', handler);\n\n// ✅ Cleanup when done\nconst handler = () => { /* ... */ };\nwindow.addEventListener('resize', handler);\n\n// Later, when component unmounts:\nwindow.removeEventListener('resize', handler);\n\n// ✅ Using AbortController\nconst controller = new AbortController();\nwindow.addEventListener('resize', handler, { signal: controller.signal });\n\n// Cleanup:\ncontroller.abort();\n```\n\n---\n\n## Code quality\n\n### Valid HTML\n\n```html\n<!-- ❌ Invalid HTML -->\n<div id=\"header\">\n<div id=\"header\"> <!-- Duplicate ID -->\n\n<ul>\n  <div>Item</div> <!-- Invalid child -->\n</ul>\n\n<a href=\"/\"><button>Click</button></a> <!-- Invalid nesting -->\n\n<!-- ✅ Valid HTML -->\n<header id=\"site-header\">\n</header>\n\n<ul>\n  <li>Item</li>\n</ul>\n\n<a href=\"/\" class=\"button\">Click</a>\n```\n\n### Semantic HTML\n\n```html\n<!-- ❌ Non-semantic -->\n<div class=\"header\">\n  <div class=\"nav\">\n    <div class=\"nav-item\">Home</div>\n  </div>\n</div>\n<div class=\"main\">\n  <div class=\"article\">\n    <div class=\"title\">Headline</div>\n  </div>\n</div>\n\n<!-- ✅ Semantic HTML5 -->\n<header>\n  <nav>\n    <a href=\"/\">Home</a>\n  </nav>\n</header>\n<main>\n  <article>\n    <h1>Headline</h1>\n  </article>\n</main>\n```\n\n### Image aspect ratios\n\n```html\n<!-- ❌ Distorted images -->\n<img src=\"photo.jpg\" width=\"300\" height=\"100\">\n<!-- If actual ratio is 4:3, this squishes the image -->\n\n<!-- ✅ Preserve aspect ratio -->\n<img src=\"photo.jpg\" width=\"300\" height=\"225\">\n<!-- Actual 4:3 dimensions -->\n\n<!-- ✅ CSS object-fit for flexibility -->\n<img src=\"photo.jpg\" style=\"width: 300px; height: 200px; object-fit: cover;\">\n```\n\n---\n\n## Permissions & privacy\n\n### Request permissions properly\n\n```javascript\n// ❌ Request on page load (bad UX, often denied)\nnavigator.geolocation.getCurrentPosition(success, error);\n\n// ✅ Request in context, after user action\nfindNearbyButton.addEventListener('click', async () => {\n  // Explain why you need it\n  if (await showPermissionExplanation()) {\n    navigator.geolocation.getCurrentPosition(success, error);\n  }\n});\n```\n\n### Permissions policy\n\n```html\n<!-- Restrict powerful features -->\n<meta http-equiv=\"Permissions-Policy\" \n      content=\"geolocation=(), camera=(), microphone=()\">\n\n<!-- Or allow for specific origins -->\n<meta http-equiv=\"Permissions-Policy\" \n      content=\"geolocation=(self 'https://maps.example.com')\">\n```\n\n---\n\n## Audit checklist\n\n### Security (critical)\n- [ ] HTTPS enabled, no mixed content\n- [ ] No vulnerable dependencies (`npm audit`)\n- [ ] CSP headers configured\n- [ ] Security headers present\n- [ ] No exposed source maps\n\n### Compatibility\n- [ ] Valid HTML5 doctype\n- [ ] Charset declared first in head\n- [ ] Viewport meta tag present\n- [ ] No deprecated APIs used\n- [ ] Passive event listeners for scroll/touch\n\n### Code quality\n- [ ] No console errors\n- [ ] Valid HTML (no duplicate IDs)\n- [ ] Semantic HTML elements used\n- [ ] Proper error handling\n- [ ] Memory cleanup in components\n\n### UX\n- [ ] No intrusive interstitials\n- [ ] Permission requests in context\n- [ ] Clear error messages\n- [ ] Appropriate image aspect ratios\n\n## Tools\n\n| Tool | Purpose |\n|------|---------|\n| `npm audit` | Dependency vulnerabilities |\n| [SecurityHeaders.com](https://securityheaders.com) | Header analysis |\n| [W3C Validator](https://validator.w3.org) | HTML validation |\n| Lighthouse | Best practices audit |\n| [Observatory](https://observatory.mozilla.org) | Security scan |\n\n## References\n\n- [MDN Web Security](https://developer.mozilla.org/en-US/docs/Web/Security)\n- [OWASP Top 10](https://owasp.org/www-project-top-ten/)\n- [Web Quality Audit](../web-quality-audit/SKILL.md)\n","src/resources/skills/btw/SKILL.md":"---\nname: btw\ndescription: Ask a quick side question about your current work without derailing the main task. Answers from existing conversation context only — no tool calls, no file reads, single concise response. Use when you need a fast answer from what is already in this session.\n---\n\n<objective>\nAnswer a quick side question using only what is already present in the current conversation context. Do not read files, run commands, search, or use any tools. Give a single, concise response and return focus to the main work.\n</objective>\n\n<behavior>\n**This is a side question, not a task.**\n\n- Answer only from information already in the conversation (files read, decisions made, code seen, context established)\n- Do NOT use any tools — no Read, no Bash, no Grep, no Search\n- If the answer requires reading something new, say so briefly and suggest the user ask as a normal prompt instead\n- Keep the response short and direct — one to a few sentences unless the question genuinely needs more\n- Do not summarize the main work, ask follow-up questions, or offer to do anything else\n- After answering, stop — do not prompt for next steps\n</behavior>\n\n<quick_start>\nParse the argument after `/btw` as the question. Answer it directly from context.\n\nIf no argument is provided, ask: \"What did you want to know?\"\n\nIf the question cannot be answered from current context (requires reading a file, running a command, or information not yet in the session), respond with:\n\"I'd need to [read X / run Y / look up Z] to answer that — ask it as a normal prompt when you're ready.\"\n</quick_start>\n\n<examples>\n**Good uses of /btw:**\n- `/btw what was the name of that config file again?` → answers from files already read in session\n- `/btw which branch are we on?` → answers from git context already established\n- `/btw did we already handle the null case in that function?` → answers from code already reviewed\n- `/btw what model does this use?` → answers from code or config already in context\n\n**Not a good fit for /btw (suggest normal prompt):**\n- Questions requiring reading a file not yet seen\n- Questions requiring running a command\n- Questions needing a multi-step answer or follow-up\n- Starting a new task or changing direction\n</examples>\n","src/resources/skills/code-optimizer/SKILL.md":"---\nname: code-optimizer\ndescription: >\n  Deep code optimization audit using parallel specialist agents. Each agent hunts for performance\n  anti-patterns, inefficiencies, and suboptimal code using pattern-based detection (Grep/Glob)\n  WITHOUT reading the full source code first — avoiding anchoring bias on existing implementations.\n  Covers ALL optimization domains: database queries, memory leaks, algorithmic complexity,\n  concurrency, bundle size, dead code, I/O & network, rendering/UI, data structures,\n  error handling, caching, build config, security-performance, logging, and infrastructure.\n  Use when asked to: \"optimize my code\", \"find performance issues\", \"audit code quality\",\n  \"speed up my app\", \"find bottlenecks\", \"code review for performance\", \"find anti-patterns\",\n  \"improve code efficiency\", \"reduce latency\", \"optimize performance\", \"code smell detection\",\n  \"find slow code\", \"optimize this project\", \"performance audit\", \"code optimization\".\n  Also triggers on: \"optimizar codigo\", \"encontrar cuellos de botella\", \"mejorar rendimiento\".\n---\n\n# Code Optimizer\n\nParallel multi-agent code optimization audit. Spawn 13 specialist agents simultaneously, each\nhunting for a different class of performance problem using pattern-based detection.\n\n## Critical Principle: No Code Reading Before Analysis\n\nAgents MUST NOT read source files before searching for patterns. Reading the code first causes\nanchoring bias — the agent accepts the existing implementation as \"reasonable\" and misses\nbetter alternatives. Instead, each agent:\n\n1. Read its assigned reference file from `references/` to load detection patterns\n2. Use Grep/Glob to scan the codebase for anti-patterns\n3. For each finding, ONLY THEN read the surrounding context (5-10 lines) to confirm the issue\n4. Propose the optimal solution based on best practices, NOT based on the existing code\n\n## Workflow\n\n### Step 1: Detect Stack\n\nUse Glob to identify the project's tech stack:\n- `**/package.json` → Node.js/JS/TS (check for React, Next.js, Express, etc.)\n- `**/requirements.txt`, `**/pyproject.toml`, `**/setup.py` → Python\n- `**/go.mod` → Go\n- `**/Cargo.toml` → Rust\n- `**/pom.xml`, `**/build.gradle` → Java\n- `**/Gemfile` → Ruby\n- `**/Dockerfile` → Docker\n- `**/*.sql` → SQL\n- `**/webpack.config.*`, `**/vite.config.*`, `**/tsconfig.json` → Build tools\n\n### Step 2: Spawn 13 Parallel Agents\n\nLaunch ALL agents simultaneously using the Agent tool. Each agent receives:\n- Its domain name and reference file path\n- The detected tech stack (so it can focus on relevant patterns)\n- The project root path\n- Instructions to NOT read code files, only Grep/Glob for patterns\n\n**Agent definitions** (spawn all 13 in a single message):\n\n| # | Agent Name | Reference File | Focus |\n|---|-----------|----------------|-------|\n| 1 | Database & Queries | `references/database-queries.md` | N+1 queries, SELECT *, missing indexes, ORM misuse, connection pooling |\n| 2 | Memory & Resources | `references/memory-resources.md` | Memory leaks, unclosed resources, large allocations, string concat in loops |\n| 3 | Algorithmic Complexity | `references/algorithmic-complexity.md` | O(n^2) patterns, unnecessary iterations, wrong data structures for lookups |\n| 4 | Concurrency & Async | `references/concurrency-async.md` | Sequential awaits, blocking in async, race conditions, unbounded concurrency |\n| 5 | Bundle & Dependencies | `references/bundle-dependencies.md` | Heavy imports, unused deps, duplicate libs, missing lazy loading |\n| 6 | Dead Code & Redundancy | `references/dead-code-redundancy.md` | Unused exports, commented code, dead branches, duplicate logic |\n| 7 | I/O & Network | `references/io-network.md` | Sequential requests, missing batching, no dedup, missing compression |\n| 8 | Rendering & UI | `references/rendering-ui.md` | Re-renders, missing virtualization, layout thrashing, animation perf |\n| 9 | Data Structures | `references/data-structures.md` | Wrong structures, unnecessary copies, inefficient serialization |\n| 10 | Error & Resilience | `references/error-resilience.md` | Missing timeouts, swallowed errors, no retries, no circuit breakers |\n| 11 | Caching & Memoization | `references/caching-memoization.md` | Missing memoization, cache without invalidation, redundant API calls |\n| 12 | Build & Compilation | `references/build-compilation.md` | Dev code in prod, missing optimization flags, slow tests, Docker issues |\n| 13 | Security-Performance | `references/security-performance.md` | Crypto misuse, missing rate limiting, ReDoS, SQL injection vectors |\n\n**Optional agents** (spawn if relevant to detected stack):\n- Logging & Observability (`references/logging-observability.md`) — if logging framework detected\n- Config & Infrastructure (`references/config-infra.md`) — if Docker/deployment config detected\n\n### Agent Prompt Template\n\nEach agent MUST receive this prompt structure:\n\n```\nYou are a {DOMAIN_NAME} optimization specialist. Your job is to find performance\nanti-patterns in the codebase at {PROJECT_ROOT}.\n\nCRITICAL RULES:\n1. DO NOT read source code files before searching. This avoids anchoring bias.\n2. First, read your reference file: {SKILL_DIR}/references/{REFERENCE_FILE}\n3. Use Grep and Glob to search for the patterns described in the reference file.\n4. Only read 5-10 lines of context around each finding to confirm it's a real issue.\n5. Skip patterns that don't match the project's stack: {DETECTED_STACK}\n\nTech stack detected: {DETECTED_STACK}\nProject root: {PROJECT_ROOT}\n\nFor each finding, report:\n- **File**: path:line_number\n- **Pattern**: what anti-pattern was detected\n- **Severity**: CRITICAL / HIGH / MEDIUM / LOW\n- **Current code**: the problematic snippet (keep short)\n- **Why it's slow**: brief explanation of the performance impact\n- **Optimal fix**: the recommended solution (code snippet or approach)\n- **Estimated impact**: qualitative improvement expected (e.g., \"10x faster for large lists\")\n\nIf you find 0 issues in your domain, report \"No issues found\" — this is a valid outcome.\nSort findings by severity (CRITICAL first).\n```\n\n### Step 3: Consolidate Report\n\nAfter all agents complete, consolidate their findings into a single prioritized report:\n\n1. Collect all findings from all agents\n2. Deduplicate (different agents may flag the same code for different reasons)\n3. Sort by severity: CRITICAL > HIGH > MEDIUM > LOW\n4. Group by file (so the user can fix file-by-file)\n5. Present the final report with:\n   - Executive summary: total findings by severity, top 3 most impactful\n   - Detailed findings table grouped by file\n   - Improvement plan: ordered list of fixes from highest to lowest impact\n\n### Report Format\n\n```markdown\n# Code Optimization Audit Report\n\n## Executive Summary\n- **X** critical issues, **Y** high, **Z** medium, **W** low\n- Top 3 highest-impact fixes:\n  1. [brief description] — [estimated impact]\n  2. [brief description] — [estimated impact]\n  3. [brief description] — [estimated impact]\n\n## Findings by File\n\n### `path/to/file.ts`\n\n| # | Severity | Domain | Pattern | Fix | Impact |\n|---|----------|--------|---------|-----|--------|\n| 1 | CRITICAL | Database | N+1 query in loop | Use prefetch_related | 50x fewer queries |\n| 2 | HIGH | Async | Sequential awaits | Use Promise.all | 3x faster |\n\n[... for each file with findings ...]\n\n## Improvement Plan\n\nPriority-ordered steps to implement the fixes:\n\n1. **[CRITICAL] Fix N+1 queries in `api/users.py`**\n   - Current: loop queries user.posts for each user\n   - Fix: add prefetch_related('posts') to queryset\n   - Impact: reduces N+1 to 2 queries\n\n2. **[HIGH] Parallelize API calls in `services/sync.ts`**\n   - Current: 5 sequential await fetch() calls\n   - Fix: Promise.all([fetch1, fetch2, ...])\n   - Impact: ~5x faster sync operation\n\n[... continue for all findings ...]\n```\n","src/resources/skills/code-optimizer/references/algorithmic-complexity.md":"# Algorithmic Complexity\n\n## Grep/Glob Patterns to Detect\n\n### O(n^2) and Worse Patterns\n```\n# Nested loops over same/related collections\nfor.*in.*\\n.*for.*in         (nested for loops)\n\\.forEach\\(.*\\.forEach\\(      (nested forEach)\n\\.map\\(.*\\.map\\(              (nested map)\n\\.filter\\(.*\\.includes\\(      (filter+includes = O(n*m))\n\\.find\\(.*inside.*\\.map\\(     (find inside map)\n\\.indexOf\\(.*inside.*for      (indexOf in loop)\n\\.includes\\(.*inside.*for     (includes in loop)\n# Array as lookup table\narray\\.find\\(.*===            (use Map/Set instead)\narray\\.some\\(.*===            (use Set.has instead)\nlist\\.index\\(                 (Python: use dict instead)\nif.*in\\s+list                 (Python: O(n) lookup in list)\n```\n\n### Unnecessary Iterations\n```\n\\.filter\\(.*\\.length          (filter just to count)\n\\.filter\\(.*\\[0\\]             (filter just to get first - use find)\n\\.map\\(.*\\.filter\\(           (map then filter - combine or reverse order)\n\\.filter\\(.*\\.map\\(.*\\.filter (multiple passes when one suffices)\n\\.sort\\(\\).*\\[0\\]             (sort to get min/max - use Math.min/max or reduce)\n\\.sort\\(\\).*\\.slice\\(0        (sort to get top-k - use partial sort/heap)\nsorted\\(.*\\)\\[0\\]             (Python: use min() instead)\nsorted\\(.*\\)\\[-1\\]            (Python: use max() instead)\n\\.reverse\\(\\).*\\.forEach      (reverse just to iterate backwards)\nObject\\.keys\\(.*\\.map\\(.*Object\\.values  (iterating keys then accessing values)\n```\n\n### Redundant Computation\n```\n# Same computation in loop\nfor.*\\n.*Math\\.              (math operations that could be hoisted)\nfor.*\\n.*\\.length            (accessing .length repeatedly - may be fine, check)\nfor.*\\n.*document\\.querySelector  (DOM queries in loops)\nfor.*\\n.*JSON\\.parse         (parsing same JSON repeatedly)\nfor.*\\n.*new RegExp\\(        (creating regex in loop)\nfor.*\\n.*new Date\\(          (creating Date objects in loop for same date)\n```\n\n### Inefficient Data Structure Choice\n```\n# Using arrays where Set/Map would be better\n\\.push\\(.*\\.includes\\(       (array as unique set)\n\\.filter\\(.*\\.indexOf\\(       (dedup with filter+indexOf)\n\\[\\].*\\.find\\(               (array for lookups)\n# Using objects where Map would be better\n\\{\\}.*\\[.*\\]\\s*=             (frequent dynamic key insertion)\ndelete.*\\[                   (frequent key deletion from object)\n```\n\n## Improvement Strategies\n\n1. **Nested loops**: Pre-build lookup Map/Set, use hash-based approaches\n2. **Filter+includes**: Convert one collection to Set for O(1) lookups\n3. **Sort for min/max**: Use Math.min/max, reduce, or heap for top-k\n4. **Multiple passes**: Combine into single reduce/loop\n5. **Redundant computation**: Hoist invariants out of loops, memoize\n6. **Array as lookup**: Use Map for key-value, Set for existence checks\n7. **String matching in loops**: Pre-compile regex, use Map for exact matches\n","src/resources/skills/code-optimizer/references/build-compilation.md":"# Build & Compilation Optimization\n\n## Grep/Glob Patterns to Detect\n\n### Unoptimized Build Config\n```\n# Webpack\nmode:\\s*['\"]development['\"]        (dev mode in production build)\ndevtool:\\s*['\"]source-map['\"]      (full source maps in production)\ndevtool:\\s*['\"]eval                (eval source maps in production)\n# No code splitting\nsplitChunks.*false                  (code splitting disabled)\n# No minification\nminimize:\\s*false                   (minification disabled)\n# Missing tree shaking\nsideEffects.*true                   (prevents tree shaking)\n```\n\n### Development-Only Code in Production\n```\nconsole\\.log\\(                     (debug logging)\nconsole\\.debug\\(                   (debug logging)\nconsole\\.trace\\(                   (trace logging)\ndebugger;                           (debugger statement)\n\\.only\\(                           (test.only left in)\n\\.skip\\(                           (test.skip left in)\nif\\s*\\(.*process\\.env\\.NODE_ENV.*development  (dev-only code)\n__DEV__                             (React Native dev flag)\n```\n\n### Missing Optimization Flags\n```\n# TypeScript\n\"strict\":\\s*false                  (strict mode disabled)\n\"skipLibCheck\":\\s*false            (slow lib checking)\n\"incremental\":\\s*false             (no incremental compilation)\n# Python\npython\\s+-O                        (check if optimized flag used)\n__debug__                           (debug-only code)\n# Docker\nFROM.*:latest                      (unpinned base image)\nRUN.*pip install(?!.*--no-cache)   (pip without --no-cache-dir)\nRUN.*npm install(?!.*--production) (npm install without --production)\nCOPY\\s+\\.\\s+\\.                     (copying entire context)\n```\n\n### Large/Slow Imports at Startup\n```\n# Top-level heavy imports that could be lazy\nimport.*tensorflow                  (heavy ML library at top)\nimport.*pandas                      (heavy data library at top)\nimport.*matplotlib                  (heavy viz library at top)\nimport.*scipy                       (heavy math library at top)\nfrom.*import\\s+\\*                   (wildcard imports slow startup)\n# Circular imports\nImportError.*circular               (circular import errors)\n```\n\n### Missing Caching in CI/CD\n```\n# No caching steps\nnpm install(?!.*cache)              (npm install without cache)\npip install(?!.*cache)              (pip install without cache)\ngo build(?!.*cache)                 (go build without cache)\ndocker build(?!.*cache)             (docker build without layer cache)\n```\n\n### Slow Test Suite\n```\n# Real I/O in tests\nfetch\\(.*test                       (real network calls in tests)\nrequests\\.\\w+\\(.*test              (real HTTP in Python tests)\nopen\\(.*test                        (real file I/O in tests)\n# No test parallelization\n--runInBand                         (Jest sequential mode)\n-p no:xdist                         (pytest parallelization disabled)\n# Heavy setup/teardown\nbeforeAll.*database                 (real DB setup in tests)\nsetUp.*database                     (real DB in Python tests)\n```\n\n## Improvement Strategies\n\n1. **Build config**: Ensure production mode, minification, tree shaking, code splitting\n2. **Dev code**: Strip console.log/debugger via build plugin (e.g., babel-plugin-transform-remove-console)\n3. **TypeScript**: Enable strict, incremental, skipLibCheck for faster builds\n4. **Docker**: Multi-stage builds, .dockerignore, layer caching, pinned versions\n5. **Lazy imports**: Move heavy imports to function scope where they're needed\n6. **CI caching**: Cache node_modules, pip cache, go build cache, Docker layers\n7. **Test speed**: Mock I/O, run tests in parallel, use in-memory DBs for integration tests\n","src/resources/skills/code-optimizer/references/bundle-dependencies.md":"# Bundle Size & Dependencies\n\n## Grep/Glob Patterns to Detect\n\n### Heavy Imports\n```\nimport\\s+\\w+\\s+from\\s+['\"]lodash['\"]      (full lodash import vs lodash/specific)\nimport\\s+\\w+\\s+from\\s+['\"]moment['\"]      (moment.js - use date-fns/dayjs)\nimport\\s+\\w+\\s+from\\s+['\"]underscore['\"]  (underscore - mostly native now)\nimport\\s+\\*\\s+as                           (wildcard imports prevent tree-shaking)\nrequire\\(['\"]lodash['\"]\\)                   (CJS lodash import)\nfrom\\s+pandas\\s+import\\s+\\*                (full pandas import)\nimport\\s+tensorflow                         (full TF import)\nimport\\s+boto3                              (full AWS SDK)\n```\n\n### Unused Dependencies\n```\n# Check package.json dependencies vs actual imports\n# Check requirements.txt vs actual imports\n# Check go.mod vs actual imports\nimport.*from.*['\"](\\w+)['\"]   (cross-reference with package.json)\n```\n\n### Duplicate Functionality\n```\n# Multiple date libraries\nmoment.*\\n.*date-fns          (both moment and date-fns)\nmoment.*\\n.*dayjs             (both moment and dayjs)\n# Multiple HTTP clients\naxios.*\\n.*node-fetch         (both axios and fetch)\naxios.*\\n.*got                (both axios and got)\n# Multiple utility libraries\nlodash.*\\n.*underscore        (both lodash and underscore)\n# Multiple state managers\nredux.*\\n.*mobx               (both redux and mobx)\nzustand.*\\n.*jotai            (multiple state libs)\n```\n\n### Dev Dependencies in Production\n```\n# devDependencies imported in src/\nimport.*from.*['\"](@testing|jest|mocha|chai|sinon|cypress|storybook)\n# Debug/test code in production\nconsole\\.log\\(\nconsole\\.debug\\(\ndebugger;\n\\.only\\(         (test.only left in)\n```\n\n### Dynamic Imports Missing\n```\n# Large components imported statically that could be lazy\nimport.*Modal       (modals are great candidates for lazy loading)\nimport.*Chart       (charts are heavy)\nimport.*Editor      (rich editors are heavy)\nimport.*PDF         (PDF libs are heavy)\nimport.*Map         (map components are heavy)\n# Route-level components not lazy loaded\nimport.*Page.*from  (page components should often be lazy)\n```\n\n### Large Assets\n```\n# Check for unoptimized assets\n\\.png['\"]          (check if could be webp/avif)\n\\.jpg['\"]          (check if could be webp/avif)\n\\.gif['\"]          (check if could be video/webp)\n\\.svg['\"].*import  (SVGs imported as modules - check size)\nbase64             (inline base64 assets)\ndata:image         (inline images)\n```\n\n## Improvement Strategies\n\n1. **Lodash**: Use `lodash-es/specific` or native equivalents (Array.find, Object.entries, etc.)\n2. **Moment.js**: Replace with date-fns or dayjs (10x smaller)\n3. **Wildcard imports**: Use named imports for tree-shaking\n4. **Unused deps**: Remove from package.json/requirements.txt\n5. **Dynamic imports**: Use React.lazy/import() for heavy, below-fold components\n6. **Images**: Convert to WebP/AVIF, use responsive srcset, lazy load below-fold\n7. **Duplicate libs**: Consolidate to one library per concern\n","src/resources/skills/code-optimizer/references/caching-memoization.md":"# Caching & Memoization\n\n## Grep/Glob Patterns to Detect\n\n### Missing Memoization\n```\n# Expensive computations without caching\ndef\\s+\\w+\\(.*\\).*:\\s*\\n.*for.*for      (Python: expensive function without @lru_cache)\nfunction\\s+\\w+\\(.*\\).*\\{.*for.*for     (JS: expensive function without memoization)\n# React missing useMemo/useCallback\nconst\\s+\\w+\\s*=\\s*\\w+\\.filter\\(        (derived data on every render)\nconst\\s+\\w+\\s*=\\s*\\w+\\.map\\(           (derived data on every render)\nconst\\s+\\w+\\s*=\\s*\\w+\\.reduce\\(        (derived data on every render)\nconst\\s+\\w+\\s*=\\s*\\w+\\.sort\\(          (sorting on every render)\n# Same computation called multiple times\n(\\w+)\\(same_args\\).*\\1\\(same_args\\)    (same function, same args, called twice)\n```\n\n### Cache Without Invalidation\n```\ncache\\s*=\\s*\\{\\}                        (cache without TTL or max size)\n_cache\\s*=\\s*\\{\\}                       (module cache without eviction)\nmemo\\s*=\\s*\\{\\}                         (memo without invalidation)\n\\.cache\\s*=\\s*\\{\\}                      (instance cache without cleanup)\nCACHE_TTL.*=.*(?:86400|3600.*24)       (very long TTL - stale data risk)\n```\n\n### Redundant API/DB Calls\n```\n# Same query executed multiple times\n\\.query\\(.*same.*\\.query\\(             (duplicate queries)\nfetch\\(['\"]same_url['\"]\\).*fetch\\(     (duplicate fetches)\n# No SWR/stale-while-revalidate\nuseEffect\\(.*fetch\\(.*\\[\\]            (fetch on every mount without caching)\nuseEffect\\(.*axios\\.\\w+\\(.*\\[\\]       (API call on every mount)\ncomponentDidMount.*fetch               (fetch without caching layer)\n```\n\n### Over-Caching\n```\n# Caching things that change frequently\ncache.*user.*session                   (caching session-specific data)\ncache.*real.?time                      (caching real-time data)\ncache.*current.*time                   (caching time-dependent data)\n# Caching large objects\ncache\\[.*\\]\\s*=\\s*.*large             (large objects in cache)\n```\n\n### Missing HTTP Caching\n```\n# API responses without cache headers\nres\\.json\\(                            (check if Cache-Control is set)\nreturn\\s+Response\\(                    (check if cache headers are set)\nreturn\\s+JsonResponse\\(               (Django: check cache headers)\n# Static assets without long cache\nexpress\\.static\\(                      (check maxAge setting)\nnginx.*location.*static               (check expires/cache-control)\n```\n\n### Computed Properties Recalculated\n```\n# Getters that compute on every access\nget\\s+\\w+\\(\\)\\s*\\{.*return.*\\.filter   (getter computing on each access)\nget\\s+\\w+\\(\\)\\s*\\{.*return.*\\.map      (getter computing on each access)\n@property\\s*\\n\\s*def.*\\n.*for          (Python property computing in loop)\n```\n\n## Improvement Strategies\n\n1. **Memoization**: Use @lru_cache (Python), useMemo/useCallback (React), _.memoize (JS)\n2. **Cache invalidation**: Always set TTL and max size; prefer LRU eviction\n3. **API caching**: Use SWR/React Query for client, Redis/Memcached for server\n4. **HTTP caching**: Set Cache-Control headers, use ETags, stale-while-revalidate\n5. **Computed properties**: Cache results with dirty flag or use memoized selectors (reselect)\n6. **Request deduplication**: Deduplicate identical in-flight requests\n7. **Multi-level cache**: L1 (in-memory) -> L2 (Redis) -> L3 (DB) for read-heavy workloads\n","src/resources/skills/code-optimizer/references/concurrency-async.md":"# Concurrency & Async Patterns\n\n## Grep/Glob Patterns to Detect\n\n### Sequential Async (Should Be Parallel)\n```\nawait.*\\n.*await.*\\n.*await    (multiple sequential awaits that could be parallel)\nfor.*await                      (sequential await in loop)\n\\.then\\(.*\\.then\\(.*\\.then\\(   (promise chain that could be Promise.all)\n# Python\nawait.*\\n.*await.*\\n.*await    (sequential awaits)\nfor.*in.*:\\n.*await            (await in loop)\n```\n\n### Missing Parallelization\n```\n# Should use Promise.all / asyncio.gather\nfetch\\(.*\\n.*fetch\\(           (sequential fetches)\naxios\\.\\w+\\(.*\\n.*axios\\.     (sequential HTTP calls)\nrequests\\.\\w+\\(.*\\n.*requests\\. (Python sequential requests)\n```\n\n### Blocking Operations in Async Context\n```\n# Node.js sync operations in async code\nfs\\.readFileSync               (blocking file read)\nfs\\.writeFileSync              (blocking file write)\nfs\\.existsSync                 (blocking existence check)\nchild_process\\.execSync        (blocking exec)\n\\.readFileSync\\(               (any sync file operation)\n# Python blocking in async\ntime\\.sleep\\(                  (use asyncio.sleep instead)\nrequests\\.                     (use aiohttp/httpx instead)\nopen\\(.*\\.read\\(\\)            (use aiofiles instead)\nos\\.path\\.exists               (use aio equivalent)\n```\n\n### Race Conditions & Thread Safety\n```\n# Shared mutable state\nglobal\\s+\\w+.*=               (Python global mutation)\nthreading\\.Thread.*shared      (shared state across threads)\n# Missing locks\n\\.append\\(.*thread             (list append without lock)\n\\+=.*without.*lock             (increment without lock)\n# JavaScript\nlet\\s+\\w+.*=.*\\n.*async       (mutable let used in async)\n```\n\n### Unbounded Concurrency\n```\n# No concurrency limit\n\\.map\\(.*fetch                 (unbounded parallel fetches)\n\\.map\\(.*axios                 (unbounded parallel requests)\nPromise\\.all\\(.*\\.map\\(        (all items in parallel, no limit)\nasyncio\\.gather\\(.*for         (all coroutines at once)\n# Missing backpressure\nwhile.*true.*await             (infinite async loop without backpressure)\n```\n\n### Error Handling in Async\n```\n# Unhandled rejections\n\\.then\\(.*without.*\\.catch     (promise without catch)\nasync.*without.*try.*catch     (async without error handling)\n# Swallowed errors\ncatch\\s*\\(\\s*\\)\\s*\\{          (empty catch block)\nexcept:\\s*$                    (bare except)\nexcept\\s+Exception\\s*:.*pass  (catch-all with pass)\n```\n\n## Improvement Strategies\n\n1. **Sequential awaits**: Use Promise.all/allSettled, asyncio.gather for independent operations\n2. **Await in loops**: Batch with Promise.all or use p-limit for controlled concurrency\n3. **Blocking in async**: Replace sync APIs with async equivalents\n4. **Race conditions**: Use locks, atomic operations, or immutable patterns\n5. **Unbounded concurrency**: Use semaphores, p-limit, connection pools\n6. **Error handling**: Always catch async errors, use Promise.allSettled for partial failure tolerance\n7. **Backpressure**: Use queues, streaming, or batching for producer-consumer patterns\n","src/resources/skills/code-optimizer/references/config-infra.md":"# Configuration & Infrastructure Inefficiencies\n\n## Grep/Glob Patterns to Detect\n\n### Missing Connection Pooling\n```\n# New connection per request\ncreate_engine\\(.*(?!.*pool)        (SQLAlchemy without pool config)\nnew Pool\\(.*(?!.*max)              (pg Pool without max connections)\nmongoose\\.connect\\(.*(?!.*pool)    (Mongoose without pool)\nDriverManager\\.getConnection\\(     (Java: new connection per call)\npsycopg2\\.connect\\(.*(?!.*pool)   (psycopg2 without pool)\nredis\\.createClient\\(.*per.*request (new Redis client per request)\n```\n\n### Missing Environment-Based Config\n```\nhardcoded.*url                     (hardcoded URLs)\n['\"]http://localhost               (hardcoded localhost URLs)\n['\"]127\\.0\\.0\\.1                   (hardcoded localhost IPs)\npassword\\s*=\\s*['\"]                (hardcoded passwords)\napi.?key\\s*=\\s*['\"]               (hardcoded API keys)\nsecret\\s*=\\s*['\"]                  (hardcoded secrets)\nport\\s*=\\s*\\d{4}                   (hardcoded port numbers)\n```\n\n### Missing Process Management\n```\n# Single-threaded Node.js without clustering\napp\\.listen\\(.*(?!.*cluster)       (Node without cluster module)\n# Python without proper WSGI/ASGI workers\n\\.run\\(.*debug=True                (Flask debug mode)\nuvicorn\\.run\\(.*workers=1          (single worker)\ngunicorn.*-w\\s*1\\b                 (single gunicorn worker)\n```\n\n### Docker/Container Issues\n```\nFROM.*:latest                      (unpinned image version)\nRUN.*apt-get.*&&.*apt-get         (check if apt cache is cleaned)\nCOPY\\s+\\.\\s+\\.                     (copying entire context - no .dockerignore)\nRUN.*npm install\\b(?!.*--production) (installing devDeps in production)\nRUN.*pip install\\b(?!.*--no-cache) (pip without cache clearing)\n# Multiple RUN commands that should be combined\nRUN.*\\nRUN.*\\nRUN                  (multiple RUN layers)\n```\n\n### Missing Health Checks\n```\n# Services without health endpoints\napp\\.(listen|start)\\(.*(?!.*health) (server without health check)\n# Docker without HEALTHCHECK\nDockerfile.*(?!.*HEALTHCHECK)       (Dockerfile without health check)\n```\n\n### Inefficient Polling\n```\nsetInterval\\(.*fetch               (polling instead of WebSocket/SSE)\nsetInterval\\(.*axios               (polling instead of push)\nwhile.*sleep.*fetch                 (polling loop)\ntime\\.sleep\\(.*requests            (Python: polling with sleep)\n```\n\n## Improvement Strategies\n\n1. **Connection pooling**: Configure pool_size, max_overflow, pool_recycle\n2. **Environment config**: Use .env files, config libraries, never hardcode secrets\n3. **Process management**: Use cluster mode (Node), multiple workers (Python ASGI/WSGI)\n4. **Docker**: Multi-stage builds, .dockerignore, combine RUN layers, pin versions\n5. **Health checks**: Add /health endpoint, Docker HEALTHCHECK, readiness/liveness probes\n6. **Polling -> Push**: Use WebSocket, SSE, or long-polling instead of interval polling\n","src/resources/skills/code-optimizer/references/data-structures.md":"# Data Structures & Serialization\n\n## Grep/Glob Patterns to Detect\n\n### Wrong Data Structure for the Job\n```\n# Array used for frequent lookups (should be Map/Set/dict)\n\\.find\\(.*===                  (linear search - use Map)\n\\.findIndex\\(.*===             (linear search for index)\n\\.includes\\(.*inside.*loop     (O(n) lookup in loop)\n\\.indexOf\\(.*inside.*loop      (O(n) lookup in loop)\nif.*in\\s+\\[                    (Python: list membership test)\nlist\\.count\\(                  (Python: counting in list)\n\n# Searching sorted data linearly (should use binary search)\n\\.find\\(.*sorted               (linear search on sorted array)\nfor.*sorted                    (iterating sorted data to find)\n\n# Using objects where Map is better (non-string keys, frequent add/delete)\n\\w+\\[\\w+\\.id\\]\\s*=             (object with dynamic keys from IDs)\ndelete\\s+\\w+\\[                 (frequent deletion from object)\nObject\\.keys\\(.*\\.length       (counting object keys - Map.size is O(1))\n\n# Using array for queue/deque operations\n\\.shift\\(\\)                    (Array.shift is O(n) - use proper queue)\n\\.unshift\\(                    (Array.unshift is O(n))\n```\n\n### Unnecessary Deep Copies\n```\nJSON\\.parse\\(JSON\\.stringify    (JSON round-trip for deep clone)\n\\.map\\(.*\\.map\\(.*spread       (nested spread for deep copy)\n\\{\\.\\.\\..*\\{\\.\\.\\.             (nested object spread)\nstructuredClone\\(.*inside.*loop (deep cloning in loop)\ncopy\\.deepcopy\\(.*loop         (Python deepcopy in loop)\nimport\\s+copy                  (check if deepcopy is overused)\n```\n\n### Inefficient Serialization\n```\n# JSON for internal communication (use binary formats)\nJSON\\.stringify.*JSON\\.parse.*internal\npickle\\.dump.*pickle\\.load     (Python: consider msgpack for cross-language)\n# Serializing more than needed\nJSON\\.stringify\\(.*entire      (serializing entire object when subset needed)\n\\.toJSON\\(\\)                   (check what's being serialized)\n# Repeated serialization\nJSON\\.stringify\\(.*loop        (stringifying in loop)\nJSON\\.parse\\(.*loop            (parsing in loop)\n```\n\n### Unnecessary Object Creation\n```\nnew Date\\(.*inside.*loop       (creating Date objects in loop)\nnew RegExp\\(.*inside.*loop     (compiling regex in loop)\nnew URL\\(.*inside.*loop        (creating URL objects in loop)\n\\.split\\(.*\\.join\\(            (split then join - use replace)\n\\.toString\\(\\).*\\.split\\(      (unnecessary string conversion)\nArray\\.from\\(.*Array\\.from\\(   (double Array.from)\n```\n\n### Immutability Overhead\n```\n# Excessive spread operators\n\\{\\.\\.\\.state,                 (spreading large state objects)\n\\[\\.\\.\\.array,                 (spreading large arrays)\n\\.map\\(.*=>.*\\{\\.\\.\\.         (creating new objects in map with spread)\n# Immer not used where it should be\nproduce\\(                      (check if immer is used consistently)\n```\n\n## Improvement Strategies\n\n1. **Array -> Map/Set**: Use Map for key-value lookups, Set for membership testing\n2. **Array.shift/unshift**: Use a proper deque/queue implementation\n3. **Deep copies**: Use structuredClone (modern), or targeted shallow copies\n4. **Serialization**: Use msgpack/protobuf for internal services, only JSON for external APIs\n5. **Object creation in loops**: Hoist object creation, reuse instances, use object pools\n6. **Large state spreads**: Use Immer's produce(), or targeted updates\n7. **Binary search**: Use on sorted data instead of linear search\n","src/resources/skills/code-optimizer/references/database-queries.md":"# Database & Query Optimization\n\n## Grep/Glob Patterns to Detect\n\n### N+1 Query Problems\n```\n# ORM loops - querying inside iterations\nfor.*in.*\\.all\\(\\)\nfor.*in.*\\.filter\\(\nfor.*in.*\\.objects\\.\n\\.prefetch_related  (absence of - check if loops exist WITHOUT prefetch)\n\\.select_related    (absence of - check if FK access exists WITHOUT select_related)\n# SQLAlchemy\nsession\\.query.*for.*in\n\\.lazy\\s*=\\s*True\n# ActiveRecord\n\\.each.*\\.where\n\\.map.*\\.find\n# Sequelize / TypeORM\nfindOne.*inside.*map\nfindOne.*inside.*for\nawait.*find.*inside.*loop\n```\n\n### Unoptimized Queries\n```\nSELECT \\*\nSELECT.*FROM.*WITHOUT.*WHERE  (full table scans)\nLIKE '%           (leading wildcard - can't use index)\nORDER BY.*RAND()\nNOT IN.*SELECT     (subquery instead of JOIN)\nDISTINCT.*SELECT \\*\nGROUP BY.*without.*index\n\\.raw\\(.*SELECT    (raw queries - potential SQL injection too)\nCOUNT\\(\\*\\).*WHERE  (count with filter vs indexed count)\n```\n\n### Missing Indexes (Heuristic)\n```\nWHERE.*=.*AND.*=    (composite queries without composite index)\nORDER BY.*multiple columns\nJOIN.*ON.*without index hint\n\\.filter\\(.*__in=   (IN queries on large sets)\n```\n\n### ORM Anti-patterns\n```\n\\.save\\(\\).*inside.*loop    (batch update instead)\n\\.create\\(\\).*inside.*loop  (bulk_create instead)\n\\.update\\(\\).*for.*in       (queryset.update instead)\nlen\\(.*\\.all\\(\\)\\)          (.count() instead)\nlist\\(.*\\.all\\(\\)\\)         (unnecessary materialization)\nif.*\\.exists\\(\\).*\\.first\\(\\)  (double query)\n\\.values\\(\\).*\\.values\\(\\)     (chained values)\n```\n\n### Connection Management\n```\n# Missing connection pooling\ncreate_engine\\(.*pool_size  (check if pool is configured)\nnew Pool\\(                   (check pool settings)\nmax_connections             (check if reasonable)\n# Unclosed connections\nconnection\\.open.*without.*close\ncursor.*without.*close\n```\n\n## Improvement Strategies\n\n1. **N+1 Queries**: Use eager loading (prefetch_related, select_related, JOIN FETCH, include/eager)\n2. **SELECT ***: Select only needed columns\n3. **Missing indexes**: Add indexes on frequently filtered/joined columns\n4. **Loop queries**: Use bulk operations (bulk_create, bulk_update, executemany)\n5. **Connection pooling**: Configure connection pools with appropriate size\n6. **Query caching**: Cache frequently-read, rarely-changing data\n7. **Pagination**: Never load unbounded result sets\n","src/resources/skills/code-optimizer/references/dead-code-redundancy.md":"# Dead Code & Redundancy\n\n## Grep/Glob Patterns to Detect\n\n### Unused Exports/Functions\n```\nexport\\s+(function|const|class)\\s+\\w+    (cross-reference: is it imported anywhere?)\ndef\\s+\\w+\\(                              (cross-reference: is it called anywhere?)\npublic\\s+(static\\s+)?\\w+\\s+\\w+\\(        (Java/C# methods - are they called?)\nfunc\\s+\\w+\\(                             (Go functions - are they called?)\n```\n\n### Unused Imports\n```\nimport.*from.*['\"].*['\"]    (cross-reference with usage in file)\nfrom\\s+\\w+\\s+import\\s+\\w+  (Python: check if imported name is used)\nrequire\\(['\"].*['\"]\\)       (CJS: check if result is used)\nuse\\s+\\w+;                  (Rust: check if used)\n```\n\n### Commented-Out Code\n```\n//\\s*(function|const|let|var|class|import|return|if|for|while)\n#\\s*(def|class|import|return|if|for|while)\n/\\*[\\s\\S]*?(function|class|import)[\\s\\S]*?\\*/\n```\n\n### Dead Branches\n```\nif\\s*\\(\\s*false\\s*\\)        (always-false condition)\nif\\s*\\(\\s*true\\s*\\)         (always-true condition - dead else)\nif\\s*\\(\\s*0\\s*\\)            (falsy constant)\nif\\s*\\(\\s*['\"]['\"]          (empty string - always falsy)\nTODO.*remove                 (TODOs indicating dead code)\nFIXME.*remove\nHACK.*temporary\n# Feature flags stuck off\nFEATURE_.*=\\s*false\nENABLE_.*=\\s*false\n```\n\n### Duplicate Logic\n```\n# Similar function signatures in same file or nearby files\nfunction\\s+\\w*(get|fetch|load|process|handle)\\w*\\(   (many similar handlers)\ndef\\s+\\w*(get|fetch|load|process|handle)\\w*\\(        (Python: similar functions)\n# Copy-paste indicators\n# Same code block appearing multiple times (use Grep to find identical blocks)\n```\n\n### Deprecated/Legacy Code\n```\n@deprecated\n@Deprecated\n# deprecated\n\\.deprecated\nDEPRECATED\nlegacy\nLegacy\nLEGACY\n__legacy__\n_old\\b\n_backup\\b\n_v[0-9]\\b       (versioned functions like process_v1)\n```\n\n### Unreachable Code\n```\nreturn.*\\n\\s*(var|let|const|function)   (code after return)\nthrow.*\\n\\s*(var|let|const|function)    (code after throw)\nexit\\(\\).*\\n                            (code after exit)\nsys\\.exit\\(.*\\n                         (Python: code after sys.exit)\nbreak\\s*;\\s*\\n\\s*\\w                     (code after break)\n```\n\n## Improvement Strategies\n\n1. **Unused exports**: Remove and verify no external consumers (check all import statements)\n2. **Unused imports**: Remove with IDE or linting tooling\n3. **Commented code**: Delete it - version control preserves history\n4. **Dead branches**: Remove unreachable code, clean up feature flags\n5. **Duplicate logic**: Extract shared function, use strategy pattern if variants differ slightly\n6. **Deprecated code**: Plan migration, remove after all callers are updated\n7. **Unreachable code**: Remove statements after return/throw/exit\n","src/resources/skills/code-optimizer/references/error-resilience.md":"# Error Handling & Resilience\n\n## Grep/Glob Patterns to Detect\n\n### Missing Timeouts\n```\nfetch\\(.*(?!.*timeout)         (fetch without timeout)\naxios\\.\\w+\\(.*(?!.*timeout)   (axios without timeout)\nrequests\\.\\w+\\(.*(?!.*timeout) (Python requests without timeout)\nhttp\\.\\w+\\(.*(?!.*timeout)    (http call without timeout)\nnew Promise\\(.*(?!.*setTimeout) (promise without timeout)\n\\.connect\\(.*(?!.*timeout)     (DB/socket connect without timeout)\n```\n\n### Swallowed Errors\n```\ncatch\\s*\\(\\s*\\w*\\s*\\)\\s*\\{\\s*\\}  (empty catch block)\ncatch\\s*\\(\\s*\\)\\s*\\{\\s*\\}        (empty catch, no error param)\nexcept:\\s*$                        (bare except)\nexcept\\s+Exception.*pass          (catch-all with pass)\nexcept\\s+Exception.*continue      (catch-all with continue)\n\\.catch\\(\\s*\\(\\)\\s*=>\\s*\\{\\s*\\}\\) (empty .catch handler)\n\\.catch\\(\\s*\\(\\)\\s*=>\\s*null\\)    (swallowing with null)\non_error.*pass                     (error handler that does nothing)\n```\n\n### Missing Retries for Transient Failures\n```\n# Network calls without retry logic\nfetch\\(.*(?!.*retry)           (fetch without retry)\naxios\\.\\w+\\(.*(?!.*retry)     (API call without retry)\nrequests\\.\\w+\\(.*(?!.*retry)  (Python request without retry)\n# Database operations without retry\n\\.query\\(.*(?!.*retry)         (DB query without retry)\n\\.execute\\(.*(?!.*retry)       (DB execute without retry)\n```\n\n### No Circuit Breaker\n```\n# Repeated calls to potentially failing services without circuit breaking\nwhile.*retry.*fetch            (retry loop without circuit break)\nMAX_RETRIES.*=.*[5-9]|[1-9]\\d+ (high retry count without circuit breaker)\n```\n\n### Resource Cleanup on Error\n```\n# try without finally for resource cleanup\ntry\\s*\\{.*open.*(?!.*finally)   (open resource without finally)\ntry:.*open\\(.*(?!.*finally)     (Python: open without finally or context manager)\n# Async cleanup missing\nasync.*try.*(?!.*finally)       (async operation without cleanup)\n```\n\n### Cascading Failures\n```\n# No fallback/default values\n\\?\\?.*undefined                 (check fallback quality)\n\\|\\|.*null                      (check fallback quality)\n\\.get\\(.*,\\s*None\\)            (Python: check if None is appropriate default)\n# No graceful degradation\ncatch.*throw                    (catching just to re-throw - no degradation)\ncatch.*return\\s+null            (returning null on error - caller may not handle)\n```\n\n### Logging Without Action\n```\nconsole\\.error\\(.*(?!.*throw|return|retry)  (logging error but not handling it)\nlogger\\.error\\(.*(?!.*raise|return|retry)   (Python: logging without action)\nprint\\(.*error.*(?!.*raise|return)          (print error without handling)\n```\n\n## Improvement Strategies\n\n1. **Timeouts**: Add timeouts to ALL external calls (network, DB, file I/O). Use AbortController for fetch\n2. **Swallowed errors**: At minimum log errors, prefer explicit handling or re-throwing\n3. **Retries**: Implement exponential backoff with jitter for transient failures\n4. **Circuit breakers**: Use circuit breaker pattern for external service calls\n5. **Resource cleanup**: Use try-finally, context managers, or using statements\n6. **Graceful degradation**: Return cached/default data instead of failing completely\n7. **Error propagation**: Don't catch errors you can't handle - let them bubble up\n","src/resources/skills/code-optimizer/references/io-network.md":"# I/O & Network Optimization\n\n## Grep/Glob Patterns to Detect\n\n### Sequential Requests (Should Be Batched/Parallel)\n```\nfetch\\(.*\\n.*fetch\\(           (sequential fetch calls)\naxios\\.\\w+\\(.*\\n.*axios\\.     (sequential axios calls)\nrequests\\.\\w+\\(.*\\n.*requests (sequential Python requests)\nhttp\\.\\w+\\(.*\\n.*http\\.       (sequential Node http calls)\n\\.get\\(.*\\n.*\\.get\\(           (sequential GET requests)\n\\.post\\(.*\\n.*\\.post\\(         (sequential POST requests)\n```\n\n### Missing Batching\n```\n# Individual API calls in loops\nfor.*\\n.*fetch\\(               (fetch in loop)\nfor.*\\n.*axios\\.               (axios in loop)\nfor.*\\n.*requests\\.            (requests in loop)\n\\.map\\(.*fetch                 (map with individual fetches)\n\\.forEach\\(.*fetch             (forEach with individual fetches)\n# Individual DB writes in loops\n\\.save\\(\\).*for                (save in loop - should batch)\n\\.insert\\(.*for                (insert in loop - should bulk insert)\n```\n\n### No Request Deduplication\n```\n# Same endpoint called multiple times\nfetch\\(['\"]([^'\"]+)['\"]\\)      (check for duplicate URLs)\naxios\\.\\w+\\(['\"]([^'\"]+)['\"]  (check for duplicate URLs)\nuseQuery\\(.*['\"]([^'\"]+)['\"]  (check for duplicate query keys)\n```\n\n### Missing Compression\n```\n# Large payload without compression\nContent-Type.*application/json  (check if gzip/br enabled)\nres\\.json\\(                     (response without compression middleware)\n# No compression middleware\nexpress\\(\\).*without.*compression\n```\n\n### Inefficient Serialization\n```\nJSON\\.stringify\\(.*large        (stringifying large objects)\nJSON\\.parse\\(.*JSON\\.stringify  (deep clone via JSON - use structuredClone)\npickle\\.dumps\\(                 (Python: consider msgpack/protobuf for performance)\nyaml\\.dump\\(.*yaml\\.load\\(     (YAML round-trip - slow for data exchange)\n```\n\n### Missing Streaming\n```\n\\.readFile\\(                   (read entire file vs createReadStream)\n\\.readFileSync\\(               (sync + entire file)\nbody\\.json\\(\\)                 (parse entire body vs streaming parser)\n\\.text\\(\\)                     (entire response as text)\n\\.json\\(\\).*large              (entire JSON response in memory)\nresponse\\.data                 (entire response buffered)\n```\n\n### Missing Caching Headers\n```\n# API responses without caching\nres\\.json\\(.*without.*cache-control\nres\\.send\\(.*without.*etag\n# Static assets without cache headers\nexpress\\.static\\(.*without.*maxAge\n```\n\n### Retry Without Backoff\n```\nretry.*count                   (check if exponential backoff exists)\nwhile.*retry                   (retry loop without delay increase)\ncatch.*retry                   (catch-retry without backoff)\nMAX_RETRIES                    (check backoff strategy)\n```\n\n## Improvement Strategies\n\n1. **Sequential requests**: Use Promise.all, asyncio.gather, or batch APIs\n2. **Loop requests**: Batch into single API call or use DataLoader pattern\n3. **Deduplication**: Use request deduplication (SWR, React Query, custom cache)\n4. **Compression**: Enable gzip/brotli at server and CDN level\n5. **Serialization**: Use efficient formats (protobuf, msgpack) for internal services\n6. **Streaming**: Use streams for large files/responses, NDJSON for large JSON\n7. **Caching**: Set appropriate Cache-Control, ETag, use stale-while-revalidate\n8. **Retries**: Implement exponential backoff with jitter\n","src/resources/skills/code-optimizer/references/logging-observability.md":"# Logging & Observability Performance\n\n## Grep/Glob Patterns to Detect\n\n### Excessive Logging\n```\nconsole\\.log\\(                     (console.log in production code)\nconsole\\.debug\\(                   (console.debug in production)\nprint\\(.*debug                     (Python print debugging)\nlogger\\.debug\\(.*inside.*loop      (debug logging in hot loop)\nlog\\.\\w+\\(.*inside.*for            (any logging in tight loop)\nconsole\\.log\\(JSON\\.stringify\\(    (serializing objects just to log)\n```\n\n### Expensive String Formatting in Logs\n```\n# String interpolation/formatting when log level is disabled\nlogger\\.debug\\(f\"                  (Python f-string even when debug disabled)\nlogger\\.debug\\(.*\\.format\\(        (Python .format() even when debug disabled)\nlogger\\.debug\\(`                   (JS template literal even when debug disabled)\nlogger\\.debug\\(.*\\+.*\\+            (string concat for debug log)\nJSON\\.stringify\\(.*log             (JSON stringify for logging)\n```\n\n### Missing Structured Logging\n```\nconsole\\.log\\([\"'].*:.*[\"']        (unstructured string logging)\nprint\\(.*[\"'].*:.*[\"']             (unstructured print logging)\nlogger\\.\\w+\\([\"'].*[\"'] %         (format string logging vs structured)\n```\n\n### Synchronous Logging\n```\nfs\\.writeFileSync.*log             (sync file write for logging)\nfs\\.appendFileSync.*log            (sync file append for logging)\nopen\\(.*log.*\\)\\.write\\(          (Python: sync log file write)\n```\n\n### Missing Request/Trace IDs\n```\n# API handlers without correlation IDs\napp\\.(get|post)\\(.*req.*res       (check if request ID is propagated)\n@app\\.route\\(                      (check if request ID middleware exists)\n```\n\n### Metrics Collection Overhead\n```\n# Metrics in hot paths\n\\.observe\\(.*inside.*loop         (Prometheus observe in loop)\n\\.increment\\(.*inside.*loop       (counter increment in loop)\nstatsd\\..*inside.*loop            (StatsD in loop)\n\\.timing\\(.*inside.*loop          (timing metric in loop)\nDate\\.now\\(\\).*Date\\.now\\(\\)      (manual timing - use proper instrumentation)\nperformance\\.now\\(\\).*performance (manual performance timing)\n```\n\n## Improvement Strategies\n\n1. **Console.log**: Remove from production, use proper logger with levels\n2. **Log formatting**: Use lazy evaluation - logger.debug(\"msg %s\", expensive_value) vs f-strings\n3. **Structured logging**: Use JSON structured logs for machine parsing\n4. **Async logging**: Buffer and flush logs asynchronously, don't block request handling\n5. **Request IDs**: Add correlation ID middleware, propagate through all service calls\n6. **Metrics**: Pre-aggregate metrics, use histograms instead of per-request timers in hot loops\n","src/resources/skills/code-optimizer/references/memory-resources.md":"# Memory & Resource Management\n\n## Grep/Glob Patterns to Detect\n\n### Memory Leaks\n```\n# Event listeners never removed\naddEventListener.*without.*removeEventListener\n\\.on\\(.*without.*\\.off\\(\n\\.subscribe\\(.*without.*unsubscribe\n# Timers never cleared\nsetInterval\\(.*without.*clearInterval\nsetTimeout\\(.*without.*clearTimeout\n# Global/module-level caches without eviction\nglobal.*\\[\\]        (unbounded global arrays)\nglobal.*\\{\\}        (unbounded global dicts/objects)\nmodule\\.exports.*cache.*=.*\\{\\}\n_cache\\s*=\\s*\\{\\}   (module-level cache without LRU/TTL)\n# Closures retaining references\nclosure.*large.*object\n# React-specific\nuseEffect.*without.*cleanup\nuseRef.*large.*object\n```\n\n### Unclosed Resources\n```\nopen\\(.*without.*close\nopen\\(.*without.*with\\s   (Python: not using context manager)\nnew FileReader\\(.*without.*close\ncreateReadStream\\(.*without.*destroy\ncreateWriteStream\\(.*without.*end\nfs\\.open\\(.*without.*fs\\.close\nnew Socket\\(.*without.*\\.close\nnew WebSocket\\(.*without.*\\.close\nacquire\\(.*without.*release\n```\n\n### Large Allocations\n```\nnew Array\\(\\d{5,}       (arrays > 10k elements)\nBuffer\\.alloc\\(\\d{6,}   (buffers > 1MB)\n\\.fill\\(.*\\d{6,}        (filling large arrays)\n\\.repeat\\(\\d{4,}         (string repeat large count)\nJSON\\.parse\\(.*large     (parsing large JSON in memory)\n\\.readFileSync\\(          (synchronous large file reads)\n\\.readFile\\(.*without.*stream  (reading whole file vs streaming)\n```\n\n### String Concatenation in Loops\n```\n\\+=.*string.*for\n\\+=.*\\\".*loop\nstr\\s*\\+=              (Python string concat in loop)\n\\.join\\(\\[              (check if used correctly)\n```\n\n## Improvement Strategies\n\n1. **Event listeners**: Always pair add/remove, use AbortController for bulk cleanup\n2. **Timers**: Clear intervals in cleanup/unmount, use refs for timer IDs\n3. **Caches**: Use LRU cache with max size, add TTL, use WeakMap/WeakRef where possible\n4. **File handling**: Use context managers (Python with), try-finally, or using statements\n5. **Streams**: Use streaming for large data instead of loading everything in memory\n6. **String building**: Use StringBuilder/list join pattern instead of concatenation in loops\n7. **Buffers**: Pool and reuse buffers, use streaming transforms\n","src/resources/skills/code-optimizer/references/rendering-ui.md":"# Rendering & UI Performance\n\n## Grep/Glob Patterns to Detect\n\n### React Re-render Issues\n```\n# Missing memoization\nconst\\s+\\w+\\s*=\\s*\\(\\s*\\)\\s*=>.*return\\s*\\(    (inline component definitions)\n\\w+\\s*=\\s*\\{.*\\}.*prop=                          (object literal as prop - new ref every render)\n\\w+\\s*=\\s*\\[.*\\].*prop=                          (array literal as prop)\n\\w+\\s*=\\s*\\(\\).*=>.*prop=                        (arrow function as prop - new ref every render)\nstyle=\\{\\{                                        (inline style object)\n# Context causing re-renders\nuseContext\\(                                       (check context value stability)\n<\\w+Provider\\s+value=\\{\\{                         (new object in Provider value)\n<\\w+Provider\\s+value=\\{[^}]*\\}                    (unstable provider value)\n# State management\nuseState\\(.*\\{                                     (object state - check if needs splitting)\nsetState\\(.*\\{\\.\\.\\.state                          (spreading entire state on each update)\n```\n\n### Missing Virtualization\n```\n\\.map\\(.*<\\w+                  (rendering list items - check list size)\n{items\\.map\\(                  (JSX list rendering - check if >50 items)\n\\.map\\(.*return.*<li           (list rendering without virtualization)\n\\.map\\(.*return.*<tr           (table row rendering without virtualization)\n\\.map\\(.*return.*<div          (div list - check count)\nv-for=                         (Vue list rendering)\nngFor                          (Angular list rendering)\n```\n\n### Layout Thrashing\n```\noffsetWidth.*style\\.           (read then write in sequence)\noffsetHeight.*style\\.          (read then write)\ngetBoundingClientRect.*style   (read then write)\nclientWidth.*className         (read then class change)\nscrollTop.*style               (read then write)\n\\.style\\..*\\.style\\.           (multiple style writes - batch with class)\n```\n\n### Large DOM\n```\ndocument\\.createElement.*loop  (creating elements in loop)\ninnerHTML\\s*\\+=                (innerHTML concatenation - causes reparse)\n\\.appendChild\\(.*loop          (appending in loop without fragment)\ndocument\\.querySelector\\(.*loop (DOM query in loop)\n\\$\\(.*\\).*loop                 (jQuery selector in loop)\n```\n\n### Missing Lazy Loading\n```\n<img\\s+(?!.*loading)           (images without loading=\"lazy\")\n<iframe\\s+(?!.*loading)        (iframes without lazy loading)\nimport.*above.*fold            (heavy imports for below-fold content)\n```\n\n### Animation Performance\n```\n# Layout-triggering animations\nanimate.*width                 (animating width triggers layout)\nanimate.*height                (animating height triggers layout)\nanimate.*top                   (animating top triggers layout)\nanimate.*left                  (animating left triggers layout)\nanimate.*margin                (animating margin triggers layout)\ntransition.*width              (transitioning layout properties)\ntransition.*height\n# Should use transform/opacity instead\n@keyframes.*\\{.*(?:width|height|top|left|margin|padding)\n```\n\n### SSR/Hydration Issues\n```\nuseEffect\\(.*\\[\\].*setState   (client-side data fetch causing hydration mismatch)\ntypeof window                  (window checks indicating SSR issues)\ndocument\\.                     (direct document access in components)\nwindow\\.                       (direct window access in components)\n```\n\n## Improvement Strategies\n\n1. **Re-renders**: Use React.memo, useMemo, useCallback for stable references\n2. **Context**: Split contexts by update frequency, memoize provider values\n3. **Virtualization**: Use react-window/react-virtuoso for lists > 50 items\n4. **Layout thrashing**: Batch reads, then batch writes; use requestAnimationFrame\n5. **DOM manipulation**: Use DocumentFragment, batch insertions, avoid innerHTML +=\n6. **Lazy loading**: Add loading=\"lazy\" to images/iframes, use Intersection Observer\n7. **Animations**: Only animate transform and opacity (GPU-composited properties)\n8. **SSR**: Pre-fetch data server-side, avoid hydration mismatches\n","src/resources/skills/code-optimizer/references/security-performance.md":"# Security-Related Performance Issues\n\n## Grep/Glob Patterns to Detect\n\n### Cryptographic Misuse\n```\nmd5\\(                              (MD5 is fast but broken - use bcrypt/argon2 for passwords)\nsha1\\(                             (SHA1 is weak)\n\\.hashSync\\(.*rounds.*[1-5]\\b     (bcrypt with low rounds)\nDES\\b                              (DES is obsolete)\nMath\\.random\\(\\).*token            (Math.random for security tokens)\nMath\\.random\\(\\).*password         (Math.random for password generation)\nrandom\\.random\\(\\).*secret         (Python: insecure random for secrets)\n```\n\n### Expensive Security Operations in Hot Paths\n```\nbcrypt.*inside.*loop               (hashing in loop - expensive by design)\njwt\\.verify\\(.*inside.*loop        (JWT verification in loop)\nencrypt\\(.*inside.*loop            (encryption in loop)\n\\.hash\\(.*inside.*loop             (hashing in loop)\n```\n\n### Missing Rate Limiting\n```\napp\\.(get|post|put|delete)\\(       (routes without rate limiting)\n@app\\.route\\(                      (Flask routes without rate limiting)\nrouter\\.(get|post|put|delete)\\(    (Express routes without rate limiting)\n```\n\n### SQL Injection Vectors (Also Performance)\n```\nf\"SELECT.*\\{                       (Python f-string SQL)\nf\"INSERT.*\\{                       (Python f-string SQL)\n`SELECT.*\\$\\{                      (JS template literal SQL)\n\"SELECT.*\" \\+ \\w+                  (string concat SQL)\n'SELECT.*' \\+ \\w+                  (string concat SQL)\n\\.raw\\(.*\\+                        (raw query with concatenation)\n\\.execute\\(.*%.*%                  (Python format string SQL)\n```\n\n### ReDoS Vulnerable Patterns\n```\n\\(\\.\\*\\)\\+                         (catastrophic backtracking)\n\\(\\.\\+\\)\\+                         (catastrophic backtracking)\n\\([^)]*\\|[^)]*\\)\\+                (alternation with repetition)\n\\(\\[.*\\]\\+\\)\\+                    (nested quantifiers)\nnew RegExp\\(.*user                 (user input in regex)\nre\\.compile\\(.*user                (Python: user input in regex)\n```\n\n### N+1 Auth Checks\n```\n# Checking permissions inside loops\n\\.can\\(.*inside.*loop             (permission check in loop)\n\\.authorize\\(.*inside.*loop       (authorization in loop)\nisAllowed\\(.*inside.*loop         (permission check in loop)\nhasPermission\\(.*inside.*loop     (permission check in loop)\n```\n\n## Improvement Strategies\n\n1. **Crypto**: Use bcrypt/argon2 for passwords, SHA-256+ for hashing, crypto.randomBytes for tokens\n2. **Hot path crypto**: Cache JWT verification results, batch encrypt/decrypt\n3. **Rate limiting**: Add rate limiters (express-rate-limit, django-ratelimit, etc.)\n4. **SQL injection**: Use parameterized queries/prepared statements (also faster due to query plan caching)\n5. **ReDoS**: Audit regex patterns, use RE2 engine, set regex timeouts\n6. **Auth batching**: Batch permission checks, pre-load permissions per request\n","src/resources/skills/core-web-vitals/SKILL.md":"---\nname: core-web-vitals\ndescription: Optimize Core Web Vitals (LCP, INP, CLS) for better page experience and search ranking. Use when asked to \"improve Core Web Vitals\", \"fix LCP\", \"reduce CLS\", \"optimize INP\", \"page experience optimization\", or \"fix layout shifts\".\nlicense: MIT\nmetadata:\n  author: web-quality-skills\n  version: \"1.0\"\n---\n\n# Core Web Vitals optimization\n\nTargeted optimization for the three Core Web Vitals metrics that affect Google Search ranking and user experience.\n\n## The three metrics\n\n| Metric | Measures | Good | Needs work | Poor |\n|--------|----------|------|------------|------|\n| **LCP** | Loading | ≤ 2.5s | 2.5s – 4s | > 4s |\n| **INP** | Interactivity | ≤ 200ms | 200ms – 500ms | > 500ms |\n| **CLS** | Visual Stability | ≤ 0.1 | 0.1 – 0.25 | > 0.25 |\n\nGoogle measures at the **75th percentile** — 75% of page visits must meet \"Good\" thresholds.\n\n---\n\n## LCP: Largest Contentful Paint\n\nLCP measures when the largest visible content element renders. Usually this is:\n- Hero image or video\n- Large text block\n- Background image\n- `<svg>` element\n\n### Common LCP issues\n\n**1. Slow server response (TTFB > 800ms)**\n```\nFix: CDN, caching, optimized backend, edge rendering\n```\n\n**2. Render-blocking resources**\n```html\n<!-- ❌ Blocks rendering -->\n<link rel=\"stylesheet\" href=\"/all-styles.css\">\n\n<!-- ✅ Critical CSS inlined, rest deferred -->\n<style>/* Critical above-fold CSS */</style>\n<link rel=\"preload\" href=\"/styles.css\" as=\"style\" \n      onload=\"this.onload=null;this.rel='stylesheet'\">\n```\n\n**3. Slow resource load times**\n```html\n<!-- ❌ No hints, discovered late -->\n<img src=\"/hero.jpg\" alt=\"Hero\">\n\n<!-- ✅ Preloaded with high priority -->\n<link rel=\"preload\" href=\"/hero.webp\" as=\"image\" fetchpriority=\"high\">\n<img src=\"/hero.webp\" alt=\"Hero\" fetchpriority=\"high\">\n```\n\n**4. Client-side rendering delays**\n```javascript\n// ❌ Content loads after JavaScript\nuseEffect(() => {\n  fetch('/api/hero-text').then(r => r.json()).then(setHeroText);\n}, []);\n\n// ✅ Server-side or static rendering\n// Use SSR, SSG, or streaming to send HTML with content\nexport async function getServerSideProps() {\n  const heroText = await fetchHeroText();\n  return { props: { heroText } };\n}\n```\n\n### LCP optimization checklist\n\n```markdown\n- [ ] TTFB < 800ms (use CDN, edge caching)\n- [ ] LCP image preloaded with fetchpriority=\"high\"\n- [ ] LCP image optimized (WebP/AVIF, correct size)\n- [ ] Critical CSS inlined (< 14KB)\n- [ ] No render-blocking JavaScript in <head>\n- [ ] Fonts don't block text rendering (font-display: swap)\n- [ ] LCP element in initial HTML (not JS-rendered)\n```\n\n### LCP element identification\n```javascript\n// Find your LCP element\nnew PerformanceObserver((list) => {\n  const entries = list.getEntries();\n  const lastEntry = entries[entries.length - 1];\n  console.log('LCP element:', lastEntry.element);\n  console.log('LCP time:', lastEntry.startTime);\n}).observe({ type: 'largest-contentful-paint', buffered: true });\n```\n\n---\n\n## INP: Interaction to Next Paint\n\nINP measures responsiveness across ALL interactions (clicks, taps, key presses) during a page visit. It reports the worst interaction (at 98th percentile for high-traffic pages).\n\n### INP breakdown\n\nTotal INP = **Input Delay** + **Processing Time** + **Presentation Delay**\n\n| Phase | Target | Optimization |\n|-------|--------|--------------|\n| Input Delay | < 50ms | Reduce main thread blocking |\n| Processing | < 100ms | Optimize event handlers |\n| Presentation | < 50ms | Minimize rendering work |\n\n### Common INP issues\n\n**1. Long tasks blocking main thread**\n```javascript\n// ❌ Long synchronous task\nfunction processLargeArray(items) {\n  items.forEach(item => expensiveOperation(item));\n}\n\n// ✅ Break into chunks with yielding\nasync function processLargeArray(items) {\n  const CHUNK_SIZE = 100;\n  for (let i = 0; i < items.length; i += CHUNK_SIZE) {\n    const chunk = items.slice(i, i + CHUNK_SIZE);\n    chunk.forEach(item => expensiveOperation(item));\n    \n    // Yield to main thread\n    await new Promise(r => setTimeout(r, 0));\n    // Or use scheduler.yield() when available\n  }\n}\n```\n\n**2. Heavy event handlers**\n```javascript\n// ❌ All work in handler\nbutton.addEventListener('click', () => {\n  // Heavy computation\n  const result = calculateComplexThing();\n  // DOM updates\n  updateUI(result);\n  // Analytics\n  trackEvent('click');\n});\n\n// ✅ Prioritize visual feedback\nbutton.addEventListener('click', () => {\n  // Immediate visual feedback\n  button.classList.add('loading');\n  \n  // Defer non-critical work\n  requestAnimationFrame(() => {\n    const result = calculateComplexThing();\n    updateUI(result);\n  });\n  \n  // Use requestIdleCallback for analytics\n  requestIdleCallback(() => trackEvent('click'));\n});\n```\n\n**3. Third-party scripts**\n```javascript\n// ❌ Eagerly loaded, blocks interactions\n<script src=\"https://heavy-widget.com/widget.js\"></script>\n\n// ✅ Lazy loaded on interaction or visibility\nconst loadWidget = () => {\n  import('https://heavy-widget.com/widget.js')\n    .then(widget => widget.init());\n};\nbutton.addEventListener('click', loadWidget, { once: true });\n```\n\n**4. Excessive re-renders (React/Vue)**\n```javascript\n// ❌ Re-renders entire tree\nfunction App() {\n  const [count, setCount] = useState(0);\n  return (\n    <div>\n      <Counter count={count} />\n      <ExpensiveComponent /> {/* Re-renders on every count change */}\n    </div>\n  );\n}\n\n// ✅ Memoized expensive components\nconst MemoizedExpensive = React.memo(ExpensiveComponent);\n\nfunction App() {\n  const [count, setCount] = useState(0);\n  return (\n    <div>\n      <Counter count={count} />\n      <MemoizedExpensive />\n    </div>\n  );\n}\n```\n\n### INP optimization checklist\n\n```markdown\n- [ ] No tasks > 50ms on main thread\n- [ ] Event handlers complete quickly (< 100ms)\n- [ ] Visual feedback provided immediately\n- [ ] Heavy work deferred with requestIdleCallback\n- [ ] Third-party scripts don't block interactions\n- [ ] Debounced input handlers where appropriate\n- [ ] Web Workers for CPU-intensive operations\n```\n\n### INP debugging\n```javascript\n// Identify slow interactions\nnew PerformanceObserver((list) => {\n  for (const entry of list.getEntries()) {\n    if (entry.duration > 200) {\n      console.warn('Slow interaction:', {\n        type: entry.name,\n        duration: entry.duration,\n        processingStart: entry.processingStart,\n        processingEnd: entry.processingEnd,\n        target: entry.target\n      });\n    }\n  }\n}).observe({ type: 'event', buffered: true, durationThreshold: 16 });\n```\n\n---\n\n## CLS: Cumulative Layout Shift\n\nCLS measures unexpected layout shifts. A shift occurs when a visible element changes position between frames without user interaction.\n\n**CLS Formula:** `impact fraction × distance fraction`\n\n### Common CLS causes\n\n**1. Images without dimensions**\n```html\n<!-- ❌ Causes layout shift when loaded -->\n<img src=\"photo.jpg\" alt=\"Photo\">\n\n<!-- ✅ Space reserved -->\n<img src=\"photo.jpg\" alt=\"Photo\" width=\"800\" height=\"600\">\n\n<!-- ✅ Or use aspect-ratio -->\n<img src=\"photo.jpg\" alt=\"Photo\" style=\"aspect-ratio: 4/3; width: 100%;\">\n```\n\n**2. Ads, embeds, and iframes**\n```html\n<!-- ❌ Unknown size until loaded -->\n<iframe src=\"https://ad-network.com/ad\"></iframe>\n\n<!-- ✅ Reserve space with min-height -->\n<div style=\"min-height: 250px;\">\n  <iframe src=\"https://ad-network.com/ad\" height=\"250\"></iframe>\n</div>\n\n<!-- ✅ Or use aspect-ratio container -->\n<div style=\"aspect-ratio: 16/9;\">\n  <iframe src=\"https://youtube.com/embed/...\" \n          style=\"width: 100%; height: 100%;\"></iframe>\n</div>\n```\n\n**3. Dynamically injected content**\n```javascript\n// ❌ Inserts content above viewport\nnotifications.prepend(newNotification);\n\n// ✅ Insert below viewport or use transform\nconst insertBelow = viewport.bottom < newNotification.top;\nif (insertBelow) {\n  notifications.prepend(newNotification);\n} else {\n  // Animate in without shifting\n  newNotification.style.transform = 'translateY(-100%)';\n  notifications.prepend(newNotification);\n  requestAnimationFrame(() => {\n    newNotification.style.transform = '';\n  });\n}\n```\n\n**4. Web fonts causing FOUT**\n```css\n/* ❌ Font swap shifts text */\n@font-face {\n  font-family: 'Custom';\n  src: url('custom.woff2') format('woff2');\n}\n\n/* ✅ Optional font (no shift if slow) */\n@font-face {\n  font-family: 'Custom';\n  src: url('custom.woff2') format('woff2');\n  font-display: optional;\n}\n\n/* ✅ Or match fallback metrics */\n@font-face {\n  font-family: 'Custom';\n  src: url('custom.woff2') format('woff2');\n  font-display: swap;\n  size-adjust: 105%; /* Match fallback size */\n  ascent-override: 95%;\n  descent-override: 20%;\n}\n```\n\n**5. Animations triggering layout**\n```css\n/* ❌ Animates layout properties */\n.animate {\n  transition: height 0.3s, width 0.3s;\n}\n\n/* ✅ Use transform instead */\n.animate {\n  transition: transform 0.3s;\n}\n.animate.expanded {\n  transform: scale(1.2);\n}\n```\n\n### CLS optimization checklist\n\n```markdown\n- [ ] All images have width/height or aspect-ratio\n- [ ] All videos/embeds have reserved space\n- [ ] Ads have min-height containers\n- [ ] Fonts use font-display: optional or matched metrics\n- [ ] Dynamic content inserted below viewport\n- [ ] Animations use transform/opacity only\n- [ ] No content injected above existing content\n```\n\n### CLS debugging\n```javascript\n// Track layout shifts\nnew PerformanceObserver((list) => {\n  for (const entry of list.getEntries()) {\n    if (!entry.hadRecentInput) {\n      console.log('Layout shift:', entry.value);\n      entry.sources?.forEach(source => {\n        console.log('  Shifted element:', source.node);\n        console.log('  Previous rect:', source.previousRect);\n        console.log('  Current rect:', source.currentRect);\n      });\n    }\n  }\n}).observe({ type: 'layout-shift', buffered: true });\n```\n\n---\n\n## Measurement tools\n\n### Lab testing\n- **Chrome DevTools** → Performance panel, Lighthouse\n- **WebPageTest** → Detailed waterfall, filmstrip\n- **Lighthouse CLI** → `npx lighthouse <url>`\n\n### Field data (real users)\n- **Chrome User Experience Report (CrUX)** → BigQuery or API\n- **Search Console** → Core Web Vitals report\n- **web-vitals library** → Send to your analytics\n\n```javascript\nimport {onLCP, onINP, onCLS} from 'web-vitals';\n\nfunction sendToAnalytics({name, value, rating}) {\n  gtag('event', name, {\n    event_category: 'Web Vitals',\n    value: Math.round(name === 'CLS' ? value * 1000 : value),\n    event_label: rating\n  });\n}\n\nonLCP(sendToAnalytics);\nonINP(sendToAnalytics);\nonCLS(sendToAnalytics);\n```\n\n---\n\n## Framework quick fixes\n\n### Next.js\n```jsx\n// LCP: Use next/image with priority\nimport Image from 'next/image';\n<Image src=\"/hero.jpg\" priority fill alt=\"Hero\" />\n\n// INP: Use dynamic imports\nconst HeavyComponent = dynamic(() => import('./Heavy'), { ssr: false });\n\n// CLS: Image component handles dimensions automatically\n```\n\n### React\n```jsx\n// LCP: Preload in head\n<link rel=\"preload\" href=\"/hero.jpg\" as=\"image\" fetchpriority=\"high\" />\n\n// INP: Memoize and useTransition\nconst [isPending, startTransition] = useTransition();\nstartTransition(() => setExpensiveState(newValue));\n\n// CLS: Always specify dimensions in img tags\n```\n\n### Vue/Nuxt\n```vue\n<!-- LCP: Use nuxt/image with preload -->\n<NuxtImg src=\"/hero.jpg\" preload loading=\"eager\" />\n\n<!-- INP: Use async components -->\n<component :is=\"() => import('./Heavy.vue')\" />\n\n<!-- CLS: Use aspect-ratio CSS -->\n<img :style=\"{ aspectRatio: '16/9' }\" />\n```\n\n## References\n\n- [web.dev LCP](https://web.dev/articles/lcp)\n- [web.dev INP](https://web.dev/articles/inp)\n- [web.dev CLS](https://web.dev/articles/cls)\n- [Code Optimizer skill](../code-optimizer/SKILL.md)\n","src/resources/skills/core-web-vitals/references/LCP.md":"# LCP optimization reference\n\n## What is LCP?\n\nLargest Contentful Paint (LCP) measures when the largest content element in the viewport becomes visible. This is typically:\n\n- An `<img>` element\n- An `<image>` element inside `<svg>`\n- A `<video>` element with poster image\n- An element with a background image via `url()`\n- A block-level element containing text nodes\n\n## LCP timeline\n\n```\n[  Server Response  ][  Resource Load  ][  Render  ]\n       TTFB              Download         Paint\n       └─────────────────────────────────────┘\n                         LCP Time\n```\n\n## Detailed optimizations\n\n### 1. Server response time (TTFB)\n\nTarget: < 800ms\n\n**Causes:**\n- Slow server/database queries\n- No CDN/edge caching\n- Inefficient backend code\n- Cold starts (serverless)\n\n**Solutions:**\n```javascript\n// Use edge functions for dynamic content\n// Vercel example\nexport const config = { runtime: 'edge' };\n\n// Use stale-while-revalidate caching\n// Cache-Control header\nres.setHeader('Cache-Control', 's-maxage=60, stale-while-revalidate=300');\n```\n\n### 2. Resource load time\n\n**For images:**\n```html\n<!-- Preload LCP image -->\n<link rel=\"preload\" as=\"image\" href=\"/hero.webp\" \n      imagesrcset=\"/hero-400.webp 400w, /hero-800.webp 800w\"\n      imagesizes=\"100vw\"\n      fetchpriority=\"high\">\n\n<!-- Modern format with fallback -->\n<picture>\n  <source srcset=\"/hero.avif\" type=\"image/avif\">\n  <source srcset=\"/hero.webp\" type=\"image/webp\">\n  <img src=\"/hero.jpg\" width=\"1200\" height=\"600\" \n       fetchpriority=\"high\" alt=\"Hero\">\n</picture>\n```\n\n**For text (web fonts):**\n```css\n@font-face {\n  font-family: 'Heading';\n  src: url('/fonts/heading.woff2') format('woff2');\n  font-display: swap; /* Show fallback immediately */\n}\n```\n\n### 3. Render blocking resources\n\n**Critical CSS pattern:**\n```html\n<head>\n  <!-- Inline critical CSS -->\n  <style>\n    /* Only above-fold styles, < 14KB */\n    .hero { /* ... */ }\n    .nav { /* ... */ }\n  </style>\n  \n  <!-- Defer non-critical CSS -->\n  <link rel=\"preload\" href=\"/styles.css\" as=\"style\" \n        onload=\"this.onload=null;this.rel='stylesheet'\">\n</head>\n```\n\n**Defer JavaScript:**\n```html\n<!-- ❌ Blocks parsing -->\n<script src=\"/app.js\"></script>\n\n<!-- ✅ Deferred (runs after HTML parsed) -->\n<script defer src=\"/app.js\"></script>\n\n<!-- ✅ Module (deferred by default) -->\n<script type=\"module\" src=\"/app.mjs\"></script>\n```\n\n### 4. Client-side rendering\n\n**Problem:** Content not in initial HTML.\n\n**Solutions:**\n\n**Server-side rendering (SSR):**\n```javascript\n// Next.js\nexport async function getServerSideProps() {\n  const data = await fetchHeroContent();\n  return { props: { hero: data } };\n}\n```\n\n**Static site generation (SSG):**\n```javascript\n// Next.js\nexport async function getStaticProps() {\n  const data = await fetchHeroContent();\n  return { props: { hero: data }, revalidate: 3600 };\n}\n```\n\n**Streaming SSR:**\n```jsx\n// React 18+\nimport { Suspense } from 'react';\n\nfunction Page() {\n  return (\n    <Suspense fallback={<HeroSkeleton />}>\n      <Hero />\n    </Suspense>\n  );\n}\n```\n\n## Framework-specific tips\n\n### Next.js\n```jsx\nimport Image from 'next/image';\n\n// LCP image with priority\n<Image \n  src=\"/hero.jpg\"\n  priority\n  fill\n  sizes=\"100vw\"\n  alt=\"Hero\"\n/>\n```\n\n### Nuxt\n```vue\n<NuxtImg\n  src=\"/hero.jpg\"\n  preload\n  loading=\"eager\"\n  sizes=\"100vw\"\n/>\n```\n\n### Astro\n```astro\n---\nimport { Image } from 'astro:assets';\nimport hero from '../assets/hero.jpg';\n---\n<Image \n  src={hero} \n  loading=\"eager\" \n  decoding=\"sync\"\n  alt=\"Hero\" \n/>\n```\n\n## Debugging LCP\n\n```javascript\n// Identify LCP element\nnew PerformanceObserver((entryList) => {\n  const entries = entryList.getEntries();\n  const lastEntry = entries[entries.length - 1];\n  \n  console.log('LCP:', {\n    element: lastEntry.element,\n    time: lastEntry.startTime,\n    size: lastEntry.size,\n    url: lastEntry.url,\n    renderTime: lastEntry.renderTime,\n    loadTime: lastEntry.loadTime\n  });\n}).observe({ type: 'largest-contentful-paint', buffered: true });\n```\n\n## Common issues\n\n| Issue | Impact | Fix |\n|-------|--------|-----|\n| No preload for LCP image | +500-1000ms | Add `<link rel=\"preload\">` |\n| Large unoptimized image | +300-800ms | Compress, use WebP/AVIF |\n| Render-blocking CSS | +200-500ms | Inline critical CSS |\n| Slow TTFB | +300-2000ms | CDN, edge caching |\n| Client-rendered content | +500-2000ms | SSR/SSG |\n","src/resources/skills/create-gsd-extension/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2FSKILL.md -->","src/resources/skills/create-gsd-extension/references/compaction-session-control.md":"<overview>\nCustom compaction hooks, triggering compaction, and session control methods available only in command handlers.\n</overview>\n\n<custom_compaction>\nOverride default compaction behavior:\n\n```typescript\npi.on(\"session_before_compact\", async (event, ctx) => {\n  const { preparation, branchEntries, customInstructions, signal } = event;\n\n  // Option 1: Cancel\n  return { cancel: true };\n\n  // Option 2: Custom summary\n  return {\n    compaction: {\n      summary: \"Custom summary of conversation so far...\",\n      firstKeptEntryId: preparation.firstKeptEntryId,\n      tokensBefore: preparation.tokensBefore,\n    }\n  };\n});\n```\n</custom_compaction>\n\n<trigger_compaction>\nTrigger compaction programmatically from any handler:\n\n```typescript\nctx.compact({\n  customInstructions: \"Focus on the authentication changes\",\n  onComplete: (result) => ctx.ui.notify(\"Compacted!\", \"info\"),\n  onError: (error) => ctx.ui.notify(`Failed: ${error.message}`, \"error\"),\n});\n```\n</trigger_compaction>\n\n<session_control>\n**Only available in command handlers** (deadlocks in event handlers):\n\n```typescript\npi.registerCommand(\"handoff\", {\n  handler: async (args, ctx) => {\n    await ctx.waitForIdle();\n\n    // Create new session with initial context\n    const result = await ctx.newSession({\n      parentSession: ctx.sessionManager.getSessionFile(),\n      setup: async (sm) => {\n        sm.appendMessage({\n          role: \"user\",\n          content: [{ type: \"text\", text: `Context: ${args}` }],\n          timestamp: Date.now(),\n        });\n      },\n    });\n\n    if (result.cancelled) { /* extension cancelled via session_before_switch */ }\n  },\n});\n```\n\n| Method | Purpose |\n|--------|---------|\n| `ctx.waitForIdle()` | Wait for agent to finish streaming |\n| `ctx.newSession(options?)` | Create a new session |\n| `ctx.fork(entryId)` | Fork from a specific entry |\n| `ctx.navigateTree(targetId, options?)` | Navigate session tree (with optional summary) |\n| `ctx.reload()` | Hot-reload everything (treat as terminal — code after runs pre-reload version) |\n\n`navigateTree` options:\n- `summarize: boolean` — generate summary of abandoned branch\n- `customInstructions: string` — instructions for summarizer\n- `replaceInstructions: boolean` — replace default prompt entirely\n- `label: string` — label to attach to branch summary\n</session_control>\n","src/resources/skills/create-gsd-extension/references/custom-commands.md":"<overview>\nCustom slash commands — registration, argument completions, subcommand patterns, and the extended command context.\n</overview>\n\n<basic_registration>\n```typescript\npi.registerCommand(\"deploy\", {\n  description: \"Deploy to an environment\",\n  handler: async (args, ctx) => {\n    // args = everything after \"/deploy \"\n    // ctx = ExtensionCommandContext (has session control methods)\n    ctx.ui.notify(`Deploying to ${args || \"production\"}`, \"info\");\n  },\n});\n```\n</basic_registration>\n\n<argument_completions>\nAdd tab-completion for command arguments:\n\n```typescript\nimport type { AutocompleteItem } from \"@gsd/pi-tui\";\n\npi.registerCommand(\"deploy\", {\n  description: \"Deploy to an environment\",\n  getArgumentCompletions: (prefix: string): AutocompleteItem[] | null => {\n    const envs = [\"dev\", \"staging\", \"prod\"];\n    const items = envs.map(e => ({ value: e, label: e }));\n    const filtered = items.filter(i => i.value.startsWith(prefix));\n    return filtered.length > 0 ? filtered : null;\n  },\n  handler: async (args, ctx) => {\n    ctx.ui.notify(`Deploying to ${args}`, \"info\");\n  },\n});\n```\n</argument_completions>\n\n<subcommand_pattern>\nFake nested commands via first-argument parsing. Used by `/wt new|ls|switch|merge|rm`.\n\n```typescript\npi.registerCommand(\"foo\", {\n  description: \"Manage foo items: /foo new|list|delete [name]\",\n\n  getArgumentCompletions: (prefix: string) => {\n    const parts = prefix.trim().split(/\\s+/);\n\n    // First arg: subcommand\n    if (parts.length <= 1) {\n      return [\"new\", \"list\", \"delete\"]\n        .filter(cmd => cmd.startsWith(parts[0] ?? \"\"))\n        .map(cmd => ({ value: cmd, label: cmd }));\n    }\n\n    // Second arg: depends on subcommand\n    if (parts[0] === \"delete\") {\n      const items = getItemsSomehow();\n      return items\n        .filter(name => name.startsWith(parts[1] ?? \"\"))\n        .map(name => ({ value: `delete ${name}`, label: name }));\n    }\n\n    return [];\n  },\n\n  handler: async (args, ctx) => {\n    const parts = args.trim().split(/\\s+/);\n    const sub = parts[0];\n\n    switch (sub) {\n      case \"new\": /* ... */ return;\n      case \"list\": /* ... */ return;\n      case \"delete\": /* handle parts[1] */ return;\n      default:\n        ctx.ui.notify(\"Usage: /foo <new|list|delete> [name]\", \"info\");\n    }\n  },\n});\n```\n\n**Gotcha:** `\"\".trim().split(/\\s+/)` produces `['']`, not `[]`. That's why `parts.length <= 1` handles both empty and partial first arg.\n</subcommand_pattern>\n\n<command_context>\nCommand handlers get `ExtensionCommandContext` which extends `ExtensionContext` with session control methods:\n\n| Method | Purpose |\n|--------|---------|\n| `ctx.waitForIdle()` | Wait for agent to finish streaming |\n| `ctx.newSession(options?)` | Create a new session |\n| `ctx.fork(entryId)` | Fork from an entry |\n| `ctx.navigateTree(targetId, options?)` | Navigate session tree |\n| `ctx.reload()` | Hot-reload everything |\n\n**⚠️ These methods are ONLY available in command handlers.** Calling them from event handlers causes deadlocks.\n\n```typescript\npi.registerCommand(\"handoff\", {\n  handler: async (args, ctx) => {\n    await ctx.waitForIdle();\n    await ctx.newSession({\n      setup: async (sm) => {\n        sm.appendMessage({\n          role: \"user\",\n          content: [{ type: \"text\", text: `Context: ${args}` }],\n          timestamp: Date.now(),\n        });\n      },\n    });\n  },\n});\n```\n</command_context>\n\n<reload_pattern>\nExpose reload as both a command and a tool the LLM can call:\n\n```typescript\npi.registerCommand(\"reload-runtime\", {\n  description: \"Reload extensions, skills, prompts, and themes\",\n  handler: async (_args, ctx) => {\n    await ctx.reload();\n    return;  // Treat reload as terminal\n  },\n});\n\npi.registerTool({\n  name: \"reload_runtime\",\n  label: \"Reload Runtime\",\n  description: \"Reload extensions, skills, prompts, and themes\",\n  parameters: Type.Object({}),\n  async execute() {\n    pi.sendUserMessage(\"/reload-runtime\", { deliverAs: \"followUp\" });\n    return { content: [{ type: \"text\", text: \"Queued /reload-runtime as follow-up.\" }] };\n  },\n});\n```\n</reload_pattern>\n","src/resources/skills/create-gsd-extension/references/custom-rendering.md":"<overview>\nCustom rendering for tools and messages — control how they appear in the TUI.\n</overview>\n\n<tool_rendering>\nTools can provide `renderCall` (how the call looks) and `renderResult` (how the result looks):\n\n```typescript\nimport { Text } from \"@gsd/pi-tui\";\nimport { keyHint } from \"@gsd/pi-coding-agent\";\n\npi.registerTool({\n  name: \"my_tool\",\n  // ...\n\n  renderCall(args, theme) {\n    let text = theme.fg(\"toolTitle\", theme.bold(\"my_tool \"));\n    text += theme.fg(\"muted\", args.action);\n    if (args.text) text += \" \" + theme.fg(\"dim\", `\"${args.text}\"`);\n    return new Text(text, 0, 0);  // 0,0 padding — Box handles it\n  },\n\n  renderResult(result, { expanded, isPartial }, theme) {\n    // isPartial = true during streaming (onUpdate was called)\n    if (isPartial) {\n      return new Text(theme.fg(\"warning\", \"Processing...\"), 0, 0);\n    }\n\n    // expanded = user toggled expand (Ctrl+O)\n    if (result.details?.error) {\n      return new Text(theme.fg(\"error\", `Error: ${result.details.error}`), 0, 0);\n    }\n\n    let text = theme.fg(\"success\", \"✓ Done\");\n    if (!expanded) {\n      text += ` (${keyHint(\"expandTools\", \"to expand\")})`;\n    }\n    if (expanded && result.details?.items) {\n      for (const item of result.details.items) {\n        text += \"\\n  \" + theme.fg(\"dim\", item);\n      }\n    }\n    return new Text(text, 0, 0);\n  },\n});\n```\n\nIf you omit `renderCall`/`renderResult`, the built-in renderer is used. Useful for tool overrides where you just wrap logic without reimplementing UI.\n\n**Fallback:** If render methods throw, `renderCall` shows tool name, `renderResult` shows raw `content` text.\n</tool_rendering>\n\n<key_hints>\nKey hint helpers for showing keybinding info in render output:\n\n```typescript\nimport { keyHint, appKeyHint, editorKey, rawKeyHint } from \"@gsd/pi-coding-agent\";\n\n// Editor action hint (respects user keybinding config)\nkeyHint(\"expandTools\", \"to expand\")    // e.g., \"Ctrl+O to expand\"\nkeyHint(\"selectConfirm\", \"to select\")\n\n// Raw key hint (always shows literal key)\nrawKeyHint(\"Ctrl+O\", \"to expand\")\n```\n</key_hints>\n\n<message_rendering>\nRegister a renderer for custom message types:\n\n```typescript\nimport { Text } from \"@gsd/pi-tui\";\n\npi.registerMessageRenderer(\"my-extension\", (message, options, theme) => {\n  const { expanded } = options;\n  let text = theme.fg(\"accent\", `[${message.customType}] `) + message.content;\n  if (expanded && message.details) {\n    text += \"\\n\" + theme.fg(\"dim\", JSON.stringify(message.details, null, 2));\n  }\n  return new Text(text, 0, 0);\n});\n\n// Send messages that use this renderer:\npi.sendMessage({\n  customType: \"my-extension\",  // Matches renderer name\n  content: \"Status update\",\n  display: true,\n  details: { foo: \"bar\" },\n});\n```\n</message_rendering>\n\n<syntax_highlighting>\n```typescript\nimport { highlightCode, getLanguageFromPath } from \"@gsd/pi-coding-agent\";\n\nconst lang = getLanguageFromPath(\"/path/to/file.rs\");  // \"rust\"\nconst highlighted = highlightCode(code, lang, theme);\n```\n</syntax_highlighting>\n\n<best_practices>\n- Return `Text` with padding `(0, 0)` — the wrapping `Box` handles padding\n- Support `expanded` for detail on demand\n- Handle `isPartial` for streaming progress\n- Keep collapsed view compact\n- Use `\\n` for multi-line content within a single `Text`\n</best_practices>\n","src/resources/skills/create-gsd-extension/references/custom-tools.md":"<overview>\nComplete custom tools reference — registration, parameters, execution, output truncation, overrides, rendering, and dynamic registration.\n</overview>\n\n<registration>\n```typescript\nimport { Type } from \"@sinclair/typebox\";\nimport { StringEnum } from \"@gsd/pi-ai\";\n\npi.registerTool({\n  name: \"my_tool\",                    // Unique identifier (snake_case)\n  label: \"My Tool\",                   // Display name in TUI\n  description: \"What this does\",      // Full description shown to LLM\n\n  // Optional: one-liner for system prompt \"Available tools\" section\n  promptSnippet: \"Manage project todo items\",\n\n  // Optional: bullets added to system prompt \"Guidelines\" when tool is active\n  promptGuidelines: [\n    \"Use my_tool for task management instead of file edits.\"\n  ],\n\n  // Parameter schema (MUST use TypeBox)\n  parameters: Type.Object({\n    action: StringEnum([\"list\", \"add\", \"remove\"] as const),\n    text: Type.Optional(Type.String({ description: \"Item text\" })),\n    id: Type.Optional(Type.Number({ description: \"Item ID\" })),\n  }),\n\n  async execute(toolCallId, params, signal, onUpdate, ctx) {\n    // 1. Check cancellation\n    if (signal?.aborted) {\n      return { content: [{ type: \"text\", text: \"Cancelled\" }] };\n    }\n\n    // 2. Stream progress (optional)\n    onUpdate?.({\n      content: [{ type: \"text\", text: \"Working...\" }],\n      details: { progress: 50 },\n    });\n\n    // 3. Do the work\n    const result = await doWork(params);\n\n    // 4. Return result\n    return {\n      content: [{ type: \"text\", text: \"Result text for LLM\" }],  // Sent to LLM context\n      details: { data: result },                                   // For rendering & state\n    };\n  },\n\n  // Optional: custom TUI rendering\n  renderCall(args, theme) { ... },\n  renderResult(result, { expanded, isPartial }, theme) { ... },\n});\n```\n</registration>\n\n<critical_stringenum>\n**⚠️ MUST use `StringEnum` for string enum parameters:**\n\n```typescript\nimport { StringEnum } from \"@gsd/pi-ai\";\n\n// ✅ Correct — works with all providers including Google\naction: StringEnum([\"list\", \"add\", \"remove\"] as const)\n\n// ❌ BROKEN with Google's API\naction: Type.Union([Type.Literal(\"list\"), Type.Literal(\"add\")])\n```\n</critical_stringenum>\n\n<output_truncation>\nTools MUST truncate output to avoid context overflow. Built-in limit: 50KB / 2000 lines.\n\n```typescript\nimport {\n  truncateHead, truncateTail, formatSize,\n  DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES,\n} from \"@gsd/pi-coding-agent\";\n\nasync execute(toolCallId, params, signal, onUpdate, ctx) {\n  const output = await runCommand();\n  const truncation = truncateHead(output, {\n    maxLines: DEFAULT_MAX_LINES,\n    maxBytes: DEFAULT_MAX_BYTES,\n  });\n\n  let result = truncation.content;\n  if (truncation.truncated) {\n    const tempFile = writeTempFile(output);\n    result += `\\n\\n[Output truncated: ${truncation.outputLines}/${truncation.totalLines} lines`;\n    result += ` (${formatSize(truncation.outputBytes)}/${formatSize(truncation.totalBytes)}).`;\n    result += ` Full output: ${tempFile}]`;\n  }\n  return { content: [{ type: \"text\", text: result }] };\n}\n```\n\nUse `truncateHead` when beginning matters (search results, file reads). Use `truncateTail` when end matters (logs, command output).\n</output_truncation>\n\n<signaling_errors>\nThrow to signal an error (sets `isError: true`). Returning a value never sets error flag.\n\n```typescript\nasync execute(toolCallId, params) {\n  if (!isValid(params.input)) {\n    throw new Error(`Invalid input: ${params.input}`);\n  }\n  return { content: [{ type: \"text\", text: \"OK\" }], details: {} };\n}\n```\n</signaling_errors>\n\n<dynamic_registration>\nTools can be registered at any time — during load, in `session_start`, in command handlers. Available immediately without `/reload`.\n\n```typescript\npi.on(\"session_start\", async (_event, ctx) => {\n  pi.registerTool({ name: \"dynamic_tool\", ... });\n});\n```\n\nUse `pi.setActiveTools(names)` to enable/disable tools at runtime.\n</dynamic_registration>\n\n<overriding_builtins>\nRegister a tool with the same name as a built-in (`read`, `bash`, `edit`, `write`, `grep`, `find`, `ls`) to override it. **Must match exact result shape including `details` type.**\n\n```typescript\nimport { createReadTool } from \"@gsd/pi-coding-agent\";\n\npi.registerTool({\n  name: \"read\",\n  label: \"Read (Logged)\",\n  description: \"Read file contents with logging\",\n  parameters: Type.Object({\n    path: Type.String(),\n    offset: Type.Optional(Type.Number()),\n    limit: Type.Optional(Type.Number()),\n  }),\n  async execute(toolCallId, params, signal, onUpdate, ctx) {\n    console.log(`[AUDIT] Reading: ${params.path}`);\n    const builtIn = createReadTool(ctx.cwd);\n    return builtIn.execute(toolCallId, params, signal, onUpdate);\n  },\n  // Omit renderCall/renderResult to use built-in renderer\n});\n```\n\nStart with no built-in tools: `gsd --no-tools -e ./my-extension.ts`\n</overriding_builtins>\n\n<multiple_tools>\nOne extension can register multiple tools with shared state:\n\n```typescript\nexport default function (pi: ExtensionAPI) {\n  let connection = null;\n\n  pi.registerTool({ name: \"db_connect\", ... });\n  pi.registerTool({ name: \"db_query\", ... });\n  pi.registerTool({ name: \"db_close\", ... });\n\n  pi.on(\"session_shutdown\", async () => {\n    connection?.close();\n  });\n}\n```\n</multiple_tools>\n\n<path_normalization>\nSome models add `@` prefix to path arguments. Strip it:\n\n```typescript\nasync execute(toolCallId, params, signal, onUpdate, ctx) {\n  let path = params.path;\n  if (path.startsWith(\"@\")) path = path.slice(1);\n  // ...\n}\n```\n</path_normalization>\n","src/resources/skills/create-gsd-extension/references/custom-ui.md":"<overview>\nComplete custom UI reference — dialogs, persistent elements, custom components, overlays, custom editors, built-in components, keyboard input, performance, theming, and common mistakes.\n</overview>\n\n<ui_architecture>\n```\n┌─────────────────────────────────────────────────┐\n│  Custom Header (ctx.ui.setHeader)               │\n├─────────────────────────────────────────────────┤\n│  Message Area                                   │\n│  - User/assistant messages                      │\n│  - Tool calls ◄── renderCall/renderResult       │\n│  - Custom messages ◄── registerMessageRenderer  │\n├─────────────────────────────────────────────────┤\n│  Widgets (above editor) ◄── ctx.ui.setWidget    │\n├─────────────────────────────────────────────────┤\n│  Editor ◄── ctx.ui.custom() / setEditorComponent│\n├─────────────────────────────────────────────────┤\n│  Widgets (below editor) ◄── ctx.ui.setWidget    │\n├─────────────────────────────────────────────────┤\n│  Footer ◄── ctx.ui.setFooter / setStatus        │\n└─────────────────────────────────────────────────┘\n  ┌─────────────────────┐\n  │  Overlay (floating)  │ ◄── ctx.ui.custom({ overlay })\n  └─────────────────────┘\n```\n\n**11 ways to get UI on screen:**\n\n| Method | Blocks? | Replaces editor? |\n|--------|---------|-------------------|\n| `ctx.ui.select/confirm/input/editor` | Yes | Temporarily |\n| `ctx.ui.notify` | No | No |\n| `ctx.ui.setStatus` | No | No (footer) |\n| `ctx.ui.setWidget` | No | No |\n| `ctx.ui.setFooter` | No | No (replaces footer) |\n| `ctx.ui.setHeader` | No | No (replaces header) |\n| `ctx.ui.custom()` | Yes | Temporarily |\n| `ctx.ui.custom({overlay})` | Yes | No (renders on top) |\n| `ctx.ui.setEditorComponent` | No | Yes (permanently) |\n| `renderCall/renderResult` | No | No (inline in messages) |\n| `registerMessageRenderer` | No | No (inline in messages) |\n</ui_architecture>\n\n<component_interface>\nEvery visual element implements:\n\n```typescript\ninterface Component {\n  render(width: number): string[];   // Required — each line ≤ width visible chars\n  handleInput?(data: string): void;  // Optional — receive keyboard input\n  wantsKeyRelease?: boolean;         // Optional — receive key release events (Kitty protocol)\n  invalidate(): void;                // Required — clear cached render state\n}\n```\n\n**Render contract:**\n- Return array of strings, one per line\n- Each string MUST NOT exceed `width` in visible characters\n- ANSI escape codes don't count toward visible width\n- **Styles are reset at end of each line** — reapply per line\n- Return `[]` for zero-height component\n\n**Invalidation contract:**\n- Clear ALL cached render output\n- Clear any pre-baked themed strings\n- Call `super.invalidate()` if extending a built-in component\n</component_interface>\n\n<dialogs>\nBlocking dialog methods on `ctx.ui`:\n\n```typescript\nconst choice = await ctx.ui.select(\"Pick one:\", [\"A\", \"B\", \"C\"]);       // string | undefined\nconst ok = await ctx.ui.confirm(\"Delete?\", \"This cannot be undone\");    // boolean\nconst name = await ctx.ui.input(\"Name:\", \"placeholder\");                // string | undefined\nconst text = await ctx.ui.editor(\"Edit:\", \"prefilled text\");            // string | undefined\n\n// Timed auto-dismiss with countdown\nconst ok = await ctx.ui.confirm(\"Proceed?\", \"Auto-continues in 5s\", { timeout: 5000 });\n// Returns false on timeout, undefined for select/input\n\n// Manual dismissal with AbortSignal (distinguish timeout from cancel)\nconst controller = new AbortController();\nconst timeoutId = setTimeout(() => controller.abort(), 5000);\nconst ok = await ctx.ui.confirm(\"Timed\", \"Auto-cancels in 5s\", { signal: controller.signal });\nclearTimeout(timeoutId);\nif (controller.signal.aborted) { /* timed out */ }\n```\n</dialogs>\n\n<persistent_ui>\n```typescript\n// Footer status (multiple extensions can set independent entries)\nctx.ui.setStatus(\"my-ext\", \"● Active\");\nctx.ui.setStatus(\"my-ext\", undefined);  // Clear\n\n// Widgets\nctx.ui.setWidget(\"my-id\", [\"Line 1\", \"Line 2\"]);                       // Above editor\nctx.ui.setWidget(\"my-id\", [\"Below\"], { placement: \"belowEditor\" });    // Below editor\nctx.ui.setWidget(\"my-id\", (_tui, theme) => ({                          // Themed\n  render: () => [theme.fg(\"accent\", \"Styled\")],\n  invalidate: () => {},\n}));\nctx.ui.setWidget(\"my-id\", undefined);  // Clear\n\n// Working message during streaming\nctx.ui.setWorkingMessage(\"Analyzing code...\");\nctx.ui.setWorkingMessage();  // Restore default\n\n// Custom footer (full replacement)\nctx.ui.setFooter((tui, theme, footerData) => ({\n  render(width) {\n    const branch = footerData.getGitBranch();          // Only available here\n    const statuses = footerData.getExtensionStatuses(); // All setStatus values\n    return [truncateToWidth(`${branch} | model`, width)];\n  },\n  invalidate() {},\n  dispose: footerData.onBranchChange(() => tui.requestRender()),  // Reactive\n}));\nctx.ui.setFooter(undefined);  // Restore default\n\n// Custom header\nctx.ui.setHeader((tui, theme) => ({\n  render(width) { return [theme.fg(\"accent\", theme.bold(\"My Header\"))]; },\n  invalidate() {},\n}));\n\n// Editor control\nctx.ui.setEditorText(\"Prefill\");\nconst current = ctx.ui.getEditorText();\nctx.ui.pasteToEditor(\"pasted content\");  // Triggers paste handling\n\n// Tool expansion\nctx.ui.setToolsExpanded(true);\nconst expanded = ctx.ui.getToolsExpanded();\n\n// Theme management\nconst themes = ctx.ui.getAllThemes();\nctx.ui.setTheme(\"light\");\nctx.ui.theme.fg(\"accent\", \"text\");  // Access current theme\n```\n</persistent_ui>\n\n<custom_components>\n`ctx.ui.custom()` temporarily replaces the editor. Returns a value when `done()` is called.\n\n**Factory callback args:**\n\n| Argument | Type | Purpose |\n|----------|------|---------|\n| `tui` | `TUI` | `tui.requestRender()` triggers re-render after state changes |\n| `theme` | `Theme` | Current theme for styling |\n| `keybindings` | `KeybindingsManager` | App keybinding config |\n| `done` | `(value: T) => void` | Close component and return value |\n\n**Inline pattern:**\n```typescript\nconst result = await ctx.ui.custom<string | null>((tui, theme, keybindings, done) => ({\n  render(width: number): string[] {\n    return [truncateToWidth(\"Press Enter to confirm, Escape to cancel\", width)];\n  },\n  handleInput(data: string) {\n    if (matchesKey(data, Key.enter)) done(\"confirmed\");\n    if (matchesKey(data, Key.escape)) done(null);\n  },\n  invalidate() {},\n}));\n```\n\n**Class-based pattern (recommended for complex UI):**\n```typescript\nclass MyComponent {\n  private selected = 0;\n  private cachedWidth?: number;\n  private cachedLines?: string[];\n\n  constructor(\n    private tui: { requestRender: () => void },\n    private theme: Theme,\n    private items: string[],\n    private done: (value: string | null) => void,\n  ) {}\n\n  handleInput(data: string) {\n    if (matchesKey(data, Key.up) && this.selected > 0) this.selected--;\n    else if (matchesKey(data, Key.down) && this.selected < this.items.length - 1) this.selected++;\n    else if (matchesKey(data, Key.enter)) { this.done(this.items[this.selected]); return; }\n    else if (matchesKey(data, Key.escape)) { this.done(null); return; }\n    else return;\n    this.invalidate();\n    this.tui.requestRender();\n  }\n\n  render(width: number): string[] {\n    if (this.cachedLines && this.cachedWidth === width) return this.cachedLines;\n    this.cachedLines = this.items.map((item, i) =>\n      truncateToWidth((i === this.selected ? \"> \" : \"  \") + item, width)\n    );\n    this.cachedWidth = width;\n    return this.cachedLines;\n  }\n\n  invalidate() { this.cachedWidth = undefined; this.cachedLines = undefined; }\n}\n\nconst result = await ctx.ui.custom<string | null>((tui, theme, _kb, done) =>\n  new MyComponent(tui, theme, [\"A\", \"B\", \"C\"], done)\n);\n```\n\n**Composing with built-in components:**\n```typescript\nconst result = await ctx.ui.custom<string | null>((tui, theme, _kb, done) => {\n  const container = new Container();\n  container.addChild(new DynamicBorder((s: string) => theme.fg(\"accent\", s)));\n  container.addChild(new Text(theme.fg(\"accent\", theme.bold(\"Title\")), 1, 0));\n\n  const selectList = new SelectList(items, 10, {\n    selectedPrefix: (t) => theme.fg(\"accent\", t),\n    selectedText: (t) => theme.fg(\"accent\", t),\n    description: (t) => theme.fg(\"muted\", t),\n    scrollInfo: (t) => theme.fg(\"dim\", t),\n    noMatch: (t) => theme.fg(\"warning\", t),\n  });\n  selectList.onSelect = (item) => done(item.value);\n  selectList.onCancel = () => done(null);\n  container.addChild(selectList);\n\n  return {\n    render: (w) => container.render(w),\n    invalidate: () => container.invalidate(),\n    handleInput: (data) => { selectList.handleInput(data); tui.requestRender(); },\n  };\n});\n```\n</custom_components>\n\n<overlays>\nFloating modals rendered on top of everything:\n\n```typescript\nconst result = await ctx.ui.custom<string | null>(\n  (tui, theme, _kb, done) => new MyDialog({ onClose: done }),\n  {\n    overlay: true,\n    overlayOptions: {\n      anchor: \"center\",         // 9 positions (see below)\n      width: \"50%\",             // number = columns, string = percentage\n      minWidth: 40,\n      maxHeight: \"80%\",\n      margin: 2,                // All sides, or { top, right, bottom, left }\n      offsetX: 0, offsetY: 0,  // Fine-tune position\n      visible: (w, h) => w >= 80,  // Hide on narrow terminals\n    },\n    onHandle: (handle) => {\n      // handle.setHidden(true/false) — temporarily hide\n      // handle.hide() — permanently remove\n    },\n  }\n);\n```\n\n**Anchor positions:**\n```\ntop-left      top-center      top-right\nleft-center      center      right-center\nbottom-left  bottom-center  bottom-right\n```\n\n**Stacked overlays:** Multiple overlays stack (newest on top). Closing one gives focus to the one below.\n\n**⚠️ Overlay lifecycle:** Components are disposed when closed. Never reuse references — create fresh instances each time.\n</overlays>\n\n<custom_editor>\nReplace the main input editor permanently:\n\n```typescript\nimport { CustomEditor } from \"@gsd/pi-coding-agent\";\n\nclass VimEditor extends CustomEditor {\n  private mode: \"normal\" | \"insert\" = \"insert\";\n\n  handleInput(data: string): void {\n    if (matchesKey(data, \"escape\") && this.mode === \"insert\") {\n      this.mode = \"normal\"; return;\n    }\n    if (this.mode === \"insert\") { super.handleInput(data); return; }\n    switch (data) {\n      case \"i\": this.mode = \"insert\"; return;\n      case \"h\": super.handleInput(\"\\x1b[D\"); return;  // Left\n      case \"j\": super.handleInput(\"\\x1b[B\"); return;  // Down\n      case \"k\": super.handleInput(\"\\x1b[A\"); return;  // Up\n      case \"l\": super.handleInput(\"\\x1b[C\"); return;  // Right\n    }\n    if (data.length === 1 && data.charCodeAt(0) >= 32) return;  // Block printable in normal\n    super.handleInput(data);\n  }\n}\n\nctx.ui.setEditorComponent((_tui, theme, keybindings) => new VimEditor(theme, keybindings));\nctx.ui.setEditorComponent(undefined);  // Restore default\n```\n\n**Critical:** Extend `CustomEditor` (NOT `Editor`) to get app keybindings (escape to abort, ctrl+d, model switching).\n</custom_editor>\n\n<built_in_components>\n**From `@gsd/pi-tui`:**\n\n| Component | Constructor | Purpose |\n|-----------|-------------|---------|\n| `Text` | `new Text(content, paddingX, paddingY, bgFn?)` | Multi-line text with word wrap |\n| `Box` | `new Box(paddingX, paddingY, bgFn)` | Container with padding+background, `.addChild()` |\n| `Container` | `new Container()` | Vertical stack, `.addChild()`, `.removeChild()`, `.clear()` |\n| `Spacer` | `new Spacer(lines)` | Empty vertical space |\n| `Markdown` | `new Markdown(content, padX, padY, getMarkdownTheme())` | Rendered markdown with syntax highlighting |\n| `Image` | `new Image(base64, mimeType, theme, opts?)` | Image rendering (Kitty, iTerm2) |\n| `SelectList` | `new SelectList(items, maxVisible, themeOpts)` | Interactive selection with search and scrolling |\n| `SettingsList` | `new SettingsList(items, maxVisible, theme, onChange, onClose, opts?)` | Toggle settings with left/right arrows |\n| `Input` | `new Input()` | Text input field |\n| `Editor` | `new Editor(tui, editorTheme)` | Multi-line editor with undo |\n\n**SelectList usage:**\n```typescript\nconst items: SelectItem[] = [\n  { value: \"opt1\", label: \"Option 1\", description: \"First option\" },\n  { value: \"opt2\", label: \"Option 2\" },\n];\nconst selectList = new SelectList(items, 10, {\n  selectedPrefix: (t) => theme.fg(\"accent\", t),\n  selectedText: (t) => theme.fg(\"accent\", t),\n  description: (t) => theme.fg(\"muted\", t),\n  scrollInfo: (t) => theme.fg(\"dim\", t),\n  noMatch: (t) => theme.fg(\"warning\", t),\n});\nselectList.onSelect = (item) => { /* item.value */ };\nselectList.onCancel = () => { /* escape pressed */ };\n```\n\n**SettingsList usage:**\n```typescript\nconst items: SettingItem[] = [\n  { id: \"verbose\", label: \"Verbose mode\", currentValue: \"off\", values: [\"on\", \"off\"] },\n  { id: \"theme\", label: \"Theme\", currentValue: \"dark\", values: [\"dark\", \"light\", \"auto\"] },\n];\nconst settings = new SettingsList(items, 15, getSettingsListTheme(),\n  (id, newValue) => { /* setting changed */ },\n  () => { /* close requested */ },\n  { enableSearch: true },\n);\n```\n\n**From `@gsd/pi-coding-agent`:**\n\n| Component | Constructor | Purpose |\n|-----------|-------------|---------|\n| `DynamicBorder` | `new DynamicBorder((s: string) => theme.fg(\"accent\", s))` | Border line |\n| `BorderedLoader` | — | Spinner with cancel support |\n| `CustomEditor` | `new CustomEditor(theme, keybindings)` | Base class for custom editors |\n</built_in_components>\n\n<keyboard_input>\n```typescript\nimport { matchesKey, Key } from \"@gsd/pi-tui\";\n\nhandleInput(data: string) {\n  // Basic keys\n  if (matchesKey(data, Key.up)) {}\n  if (matchesKey(data, Key.down)) {}\n  if (matchesKey(data, Key.enter)) {}\n  if (matchesKey(data, Key.escape)) {}\n  if (matchesKey(data, Key.tab)) {}\n  if (matchesKey(data, Key.space)) {}\n  if (matchesKey(data, Key.backspace)) {}\n  if (matchesKey(data, Key.home)) {}\n  if (matchesKey(data, Key.end)) {}\n\n  // With modifiers\n  if (matchesKey(data, Key.ctrl(\"c\"))) {}\n  if (matchesKey(data, Key.shift(\"tab\"))) {}\n  if (matchesKey(data, Key.alt(\"left\"))) {}\n  if (matchesKey(data, Key.ctrlShift(\"p\"))) {}\n\n  // String format also works: \"enter\", \"ctrl+c\", \"shift+tab\"\n\n  // Printable character detection\n  if (data.length === 1 && data.charCodeAt(0) >= 32) {\n    // Letter, number, symbol\n  }\n}\n```\n\n**handleInput contract:**\n1. Check for your keys\n2. Update state\n3. Call `this.invalidate()` if render output changes\n4. Call `tui.requestRender()` to trigger re-render\n</keyboard_input>\n\n<line_width_rule>\n**Cardinal rule: each line from render() must not exceed `width` visible characters.**\n\n```typescript\nimport { visibleWidth, truncateToWidth, wrapTextWithAnsi } from \"@gsd/pi-tui\";\n\nvisibleWidth(\"\\x1b[32mHello\\x1b[0m\");  // Returns 5 (ignores ANSI codes)\ntruncateToWidth(\"Very long text here\", 10);         // \"Very lo...\"\ntruncateToWidth(\"Very long text here\", 10, \"\");      // \"Very long \" (no ellipsis)\nwrapTextWithAnsi(\"\\x1b[32mLong green text\\x1b[0m\", 10);  // Word wrap preserving ANSI\n```\n\nIf lines exceed `width`, terminal wraps cause visual corruption.\n</line_width_rule>\n\n<performance_caching>\nAlways cache render output:\n\n```typescript\nclass CachedComponent {\n  private cachedWidth?: number;\n  private cachedLines?: string[];\n\n  render(width: number): string[] {\n    if (this.cachedLines && this.cachedWidth === width) return this.cachedLines;\n    const lines = this.computeLines(width);\n    this.cachedWidth = width;\n    this.cachedLines = lines;\n    return lines;\n  }\n\n  invalidate() { this.cachedWidth = undefined; this.cachedLines = undefined; }\n}\n```\n\n**Update cycle:** State changes → `invalidate()` → `tui.requestRender()` → `render(width)` called\n\n**Game loop pattern** (real-time updates):\n```typescript\nthis.interval = setInterval(() => {\n  this.tick();\n  this.version++;\n  this.tui.requestRender();\n}, 100);  // 10 FPS\n\n// Clean up in dispose()\nclearInterval(this.interval);\n```\n</performance_caching>\n\n<theme_colors>\nAlways use theme from callback params, never import directly.\n\n**All foreground colors:**\n\n| Category | Colors |\n|----------|--------|\n| General | `text`, `accent`, `muted`, `dim` |\n| Status | `success`, `error`, `warning` |\n| Borders | `border`, `borderAccent`, `borderMuted` |\n| Messages | `userMessageText`, `customMessageText`, `customMessageLabel` |\n| Tools | `toolTitle`, `toolOutput` |\n| Diffs | `toolDiffAdded`, `toolDiffRemoved`, `toolDiffContext` |\n| Markdown | `mdHeading`, `mdLink`, `mdLinkUrl`, `mdCode`, `mdCodeBlock`, `mdCodeBlockBorder`, `mdQuote`, `mdQuoteBorder`, `mdHr`, `mdListBullet` |\n| Syntax | `syntaxComment`, `syntaxKeyword`, `syntaxFunction`, `syntaxVariable`, `syntaxString`, `syntaxNumber`, `syntaxType`, `syntaxOperator`, `syntaxPunctuation` |\n| Thinking | `thinkingOff`, `thinkingMinimal`, `thinkingLow`, `thinkingMedium`, `thinkingHigh`, `thinkingXhigh` |\n\n**All background colors:** `selectedBg`, `userMessageBg`, `customMessageBg`, `toolPendingBg`, `toolSuccessBg`, `toolErrorBg`\n\n**Syntax highlighting:**\n```typescript\nimport { highlightCode, getLanguageFromPath } from \"@gsd/pi-coding-agent\";\nconst lang = getLanguageFromPath(\"/file.rs\");  // \"rust\"\nconst highlighted = highlightCode(code, lang, theme);\n```\n</theme_colors>\n\n<common_mistakes>\n1. **Lines exceed width** → Visual corruption. Use `truncateToWidth()` on every line.\n2. **Forgetting `tui.requestRender()`** → UI doesn't update. Call after invalidate().\n3. **Importing theme directly** → Wrong colors after theme switch. Use theme from callback.\n4. **Not typing DynamicBorder param** → `new DynamicBorder((s: string) => theme.fg(\"accent\", s))`.\n5. **Reusing disposed overlay components** → Create fresh instances each time.\n6. **Styles bleeding across lines** → TUI resets per line. Reapply styles, or use `wrapTextWithAnsi()`.\n7. **Not implementing invalidate()** → Theme changes don't take effect.\n8. **Forgetting super.invalidate()** → `override invalidate() { super.invalidate(); /* cleanup */ }`\n9. **Timer not cleaned up** → Call `clearInterval` before `done()`.\n10. **Using ctx.ui in non-interactive mode** → Check `ctx.hasUI` first.\n</common_mistakes>\n","src/resources/skills/create-gsd-extension/references/events-reference.md":"<overview>\nComplete event reference with handler signatures, return types, and type narrowing utilities.\n</overview>\n\n<event_categories>\n\n**Session events:** `session_start`, `session_before_switch`, `session_switch`, `session_before_fork`, `session_fork`, `session_before_compact`, `session_compact`, `session_before_tree`, `session_tree`, `session_shutdown`\n\n**Agent events:** `before_agent_start`, `agent_start`, `agent_end`, `turn_start`, `turn_end`, `context`, `before_provider_request`, `message_start`, `message_update`, `message_end`\n\n**Tool events:** `tool_call`, `tool_execution_start`, `tool_execution_update`, `tool_execution_end`, `tool_result`\n\n**Input events:** `input`\n\n**Model events:** `model_select`\n\n**User bash events:** `user_bash`\n\n**Special:** `session_directory` (CLI startup only, no `ctx` — receives only event)\n\n</event_categories>\n\n<handler_signature>\n```typescript\npi.on(\"event_name\", async (event, ctx: ExtensionContext) => {\n  // event — typed payload for this event\n  // ctx — access to UI, session, model, control flow\n  // Return undefined for no action, or a typed response\n});\n```\n</handler_signature>\n\n<key_events>\n\n**before_agent_start** — Fired after user prompt, before agent loop. Primary hook for context injection and system prompt modification.\n```typescript\npi.on(\"before_agent_start\", async (event, ctx) => {\n  // event.prompt — user's prompt text\n  // event.images — attached images\n  // event.systemPrompt — current system prompt\n  return {\n    message: { customType: \"my-ext\", content: \"Extra context\", display: true },\n    systemPrompt: event.systemPrompt + \"\\n\\nExtra instructions...\",\n  };\n});\n```\n\n**tool_call** — Fired before tool executes. Can block.\n```typescript\nimport { isToolCallEventType } from \"@gsd/pi-coding-agent\";\n\npi.on(\"tool_call\", async (event, ctx) => {\n  if (isToolCallEventType(\"bash\", event)) {\n    // event.input is typed as { command: string; timeout?: number }\n    if (event.input.command.includes(\"rm -rf\")) {\n      return { block: true, reason: \"Dangerous command\" };\n    }\n  }\n});\n```\n\n**tool_result** — Fired after tool executes. Can modify result. Handlers chain like middleware.\n```typescript\nimport { isToolResultEventType } from \"@gsd/pi-coding-agent\";\n\npi.on(\"tool_result\", async (event, ctx) => {\n  if (isToolResultEventType(\"bash\", event)) {\n    // event.details is typed as BashToolDetails\n  }\n  // Return partial patch: { content, details, isError }\n  // Omitted fields keep current values\n});\n```\n\n**context** — Fired before each LLM call. Modify messages non-destructively.\n```typescript\npi.on(\"context\", async (event, ctx) => {\n  // event.messages is a deep copy — safe to modify\n  const filtered = event.messages.filter(m => !shouldPrune(m));\n  return { messages: filtered };\n});\n```\n\n**input** — Fired when user input is received, before skill/template expansion.\n```typescript\npi.on(\"input\", async (event, ctx) => {\n  // event.text — raw input\n  // event.source — \"interactive\", \"rpc\", or \"extension\"\n  if (event.text.startsWith(\"?quick \"))\n    return { action: \"transform\", text: `Respond briefly: ${event.text.slice(7)}` };\n  return { action: \"continue\" };\n});\n```\n\n**model_select** — Fired when model changes.\n```typescript\npi.on(\"model_select\", async (event, ctx) => {\n  // event.model, event.previousModel, event.source (\"set\"|\"cycle\"|\"restore\")\n});\n```\n\n</key_events>\n\n<type_narrowing>\nBuilt-in type guards for tool events:\n\n```typescript\nimport { isToolCallEventType, isToolResultEventType } from \"@gsd/pi-coding-agent\";\n\n// Tool calls — narrows event.input type\nif (isToolCallEventType(\"bash\", event)) { /* event.input: { command, timeout? } */ }\nif (isToolCallEventType(\"read\", event)) { /* event.input: { path, offset?, limit? } */ }\nif (isToolCallEventType(\"write\", event)) { /* event.input: { path, content } */ }\nif (isToolCallEventType(\"edit\", event)) { /* event.input: { path, oldText, newText } */ }\n\n// Tool results — narrows event.details type\nif (isToolResultEventType(\"bash\", event)) { /* event.details: BashToolDetails */ }\n```\n\nFor custom tools, export your input type and use explicit type params:\n```typescript\nif (isToolCallEventType<\"my_tool\", MyToolInput>(\"my_tool\", event)) {\n  event.input.action; // typed\n}\n```\n</type_narrowing>\n","src/resources/skills/create-gsd-extension/references/extension-lifecycle.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fextension-lifecycle.md -->","src/resources/skills/create-gsd-extension/references/extensionapi-reference.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fextensionapi-reference.md -->","src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fextensioncontext-reference.md -->","src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fkey-rules-gotchas.md -->","src/resources/skills/create-gsd-extension/references/mode-behavior.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fmode-behavior.md -->","src/resources/skills/create-gsd-extension/references/model-provider-management.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fmodel-provider-management.md -->","src/resources/skills/create-gsd-extension/references/packaging-distribution.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fpackaging-distribution.md -->","src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fremote-execution-overrides.md -->","src/resources/skills/create-gsd-extension/references/state-management.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fstate-management.md -->","src/resources/skills/create-gsd-extension/references/system-prompt-modification.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fsystem-prompt-modification.md -->","src/resources/skills/create-gsd-extension/workflows/add-capability.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Fworkflows%2Fadd-capability.md -->","src/resources/skills/create-gsd-extension/workflows/create-extension.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Fworkflows%2Fcreate-extension.md -->","src/resources/skills/create-gsd-extension/workflows/debug-extension.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Fworkflows%2Fdebug-extension.md -->","src/resources/skills/create-mcp-server/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-mcp-server%2FSKILL.md -->","src/resources/skills/create-skill/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2FSKILL.md -->","src/resources/skills/create-skill/references/api-security.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fapi-security.md -->","src/resources/skills/create-skill/references/be-clear-and-direct.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fbe-clear-and-direct.md -->","src/resources/skills/create-skill/references/common-patterns.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fcommon-patterns.md -->","src/resources/skills/create-skill/references/core-principles.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fcore-principles.md -->","src/resources/skills/create-skill/references/executable-code.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fexecutable-code.md -->","src/resources/skills/create-skill/references/gsd-skill-ecosystem.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fgsd-skill-ecosystem.md -->","src/resources/skills/create-skill/references/iteration-and-testing.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fiteration-and-testing.md -->","src/resources/skills/create-skill/references/recommended-structure.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Frecommended-structure.md -->","src/resources/skills/create-skill/references/skill-structure.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fskill-structure.md -->","src/resources/skills/create-skill/references/use-xml-tags.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fuse-xml-tags.md -->","src/resources/skills/create-skill/references/using-scripts.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fusing-scripts.md -->","src/resources/skills/create-skill/references/using-templates.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fusing-templates.md -->","src/resources/skills/create-skill/references/workflows-and-validation.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fworkflows-and-validation.md -->","src/resources/skills/create-skill/templates/router-skill.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Ftemplates%2Frouter-skill.md -->","src/resources/skills/create-skill/templates/simple-skill.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Ftemplates%2Fsimple-skill.md -->","src/resources/skills/create-skill/workflows/add-reference.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fadd-reference.md -->","src/resources/skills/create-skill/workflows/add-script.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fadd-script.md -->","src/resources/skills/create-skill/workflows/add-template.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fadd-template.md -->","src/resources/skills/create-skill/workflows/add-workflow.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fadd-workflow.md -->","src/resources/skills/create-skill/workflows/audit-skill.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Faudit-skill.md -->","src/resources/skills/create-skill/workflows/create-new-skill.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fcreate-new-skill.md -->","src/resources/skills/create-skill/workflows/get-guidance.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fget-guidance.md -->","src/resources/skills/create-skill/workflows/upgrade-to-router.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fupgrade-to-router.md -->","src/resources/skills/create-skill/workflows/verify-skill.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fverify-skill.md -->","src/resources/skills/create-workflow/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2FSKILL.md -->","src/resources/skills/create-workflow/references/feature-patterns.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Freferences%2Ffeature-patterns.md -->","src/resources/skills/create-workflow/references/verification-policies.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Freferences%2Fverification-policies.md -->","src/resources/skills/create-workflow/references/yaml-schema-v1.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Freferences%2Fyaml-schema-v1.md -->","src/resources/skills/create-workflow/templates/blog-post-pipeline.yaml":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Ftemplates%2Fblog-post-pipeline.yaml -->","src/resources/skills/create-workflow/templates/code-audit.yaml":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Ftemplates%2Fcode-audit.yaml -->","src/resources/skills/create-workflow/templates/release-checklist.yaml":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Ftemplates%2Frelease-checklist.yaml -->","src/resources/skills/create-workflow/templates/workflow-definition.yaml":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Ftemplates%2Fworkflow-definition.yaml -->","src/resources/skills/create-workflow/workflows/create-from-scratch.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Fworkflows%2Fcreate-from-scratch.md -->","src/resources/skills/create-workflow/workflows/create-from-template.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Fworkflows%2Fcreate-from-template.md -->","src/resources/skills/debug-like-expert/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2FSKILL.md -->","src/resources/skills/debug-like-expert/references/debugging-mindset.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2Freferences%2Fdebugging-mindset.md -->","src/resources/skills/debug-like-expert/references/hypothesis-testing.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2Freferences%2Fhypothesis-testing.md -->","src/resources/skills/debug-like-expert/references/investigation-techniques.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2Freferences%2Finvestigation-techniques.md -->","src/resources/skills/debug-like-expert/references/verification-patterns.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2Freferences%2Fverification-patterns.md -->","src/resources/skills/debug-like-expert/references/when-to-research.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2Freferences%2Fwhen-to-research.md -->","src/resources/skills/decompose-into-slices/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdecompose-into-slices%2FSKILL.md -->","src/resources/skills/dependency-upgrade/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdependency-upgrade%2FSKILL.md -->","src/resources/skills/design-an-interface/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdesign-an-interface%2FSKILL.md -->","src/resources/skills/forensics/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fforensics%2FSKILL.md -->","src/resources/skills/frontend-design/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Ffrontend-design%2FSKILL.md -->","src/resources/skills/github-workflows/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2FSKILL.md -->","src/resources/skills/github-workflows/references/gh/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2Freferences%2Fgh%2FSKILL.md -->","src/resources/skills/github-workflows/references/gh/references/issue-stories.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2Freferences%2Fgh%2Freferences%2Fissue-stories.md -->","src/resources/skills/github-workflows/references/gh/references/labels.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2Freferences%2Fgh%2Freferences%2Flabels.md -->","src/resources/skills/github-workflows/references/gh/references/milestones.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2Freferences%2Fgh%2Freferences%2Fmilestones.md -->","src/resources/skills/github-workflows/references/gh/references/projects-v2.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2Freferences%2Fgh%2Freferences%2Fprojects-v2.md -->","src/resources/skills/grill-me/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgrill-me%2FSKILL.md -->","src/resources/skills/handoff/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fhandoff%2FSKILL.md -->","src/resources/skills/lint/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Flint%2FSKILL.md -->","src/resources/skills/make-interfaces-feel-better/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fmake-interfaces-feel-better%2FSKILL.md -->","src/resources/skills/make-interfaces-feel-better/animations.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fmake-interfaces-feel-better%2Fanimations.md -->","src/resources/skills/make-interfaces-feel-better/performance.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fmake-interfaces-feel-better%2Fperformance.md -->","src/resources/skills/make-interfaces-feel-better/surfaces.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fmake-interfaces-feel-better%2Fsurfaces.md -->","src/resources/skills/make-interfaces-feel-better/typography.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fmake-interfaces-feel-better%2Ftypography.md -->","src/resources/skills/observability/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fobservability%2FSKILL.md -->","src/resources/skills/react-best-practices/README.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2FREADME.md -->","src/resources/skills/react-best-practices/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2FSKILL.md -->","src/resources/skills/react-best-practices/metadata.json":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Fmetadata.json -->","src/resources/skills/react-best-practices/rules/_sections.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2F_sections.md -->","src/resources/skills/react-best-practices/rules/_template.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2F_template.md -->","src/resources/skills/react-best-practices/rules/advanced-event-handler-refs.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fadvanced-event-handler-refs.md -->","src/resources/skills/react-best-practices/rules/advanced-init-once.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fadvanced-init-once.md -->","src/resources/skills/react-best-practices/rules/advanced-use-latest.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fadvanced-use-latest.md -->","src/resources/skills/react-best-practices/rules/async-api-routes.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fasync-api-routes.md -->","src/resources/skills/react-best-practices/rules/async-defer-await.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fasync-defer-await.md -->","src/resources/skills/react-best-practices/rules/async-dependencies.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fasync-dependencies.md -->","src/resources/skills/react-best-practices/rules/async-parallel.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fasync-parallel.md -->","src/resources/skills/react-best-practices/rules/async-suspense-boundaries.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fasync-suspense-boundaries.md -->","src/resources/skills/react-best-practices/rules/bundle-barrel-imports.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fbundle-barrel-imports.md -->","src/resources/skills/react-best-practices/rules/bundle-conditional.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fbundle-conditional.md -->","src/resources/skills/react-best-practices/rules/bundle-defer-third-party.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fbundle-defer-third-party.md -->","src/resources/skills/react-best-practices/rules/bundle-dynamic-imports.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fbundle-dynamic-imports.md -->","src/resources/skills/react-best-practices/rules/bundle-preload.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fbundle-preload.md -->","src/resources/skills/react-best-practices/rules/client-event-listeners.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fclient-event-listeners.md -->","src/resources/skills/react-best-practices/rules/client-localstorage-schema.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fclient-localstorage-schema.md -->","src/resources/skills/react-best-practices/rules/client-passive-event-listeners.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fclient-passive-event-listeners.md -->","src/resources/skills/react-best-practices/rules/client-swr-dedup.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fclient-swr-dedup.md -->","src/resources/skills/react-best-practices/rules/js-batch-dom-css.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-batch-dom-css.md -->","src/resources/skills/react-best-practices/rules/js-cache-function-results.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-cache-function-results.md -->","src/resources/skills/react-best-practices/rules/js-cache-property-access.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-cache-property-access.md -->","src/resources/skills/react-best-practices/rules/js-cache-storage.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-cache-storage.md -->","src/resources/skills/react-best-practices/rules/js-combine-iterations.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-combine-iterations.md -->","src/resources/skills/react-best-practices/rules/js-early-exit.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-early-exit.md -->","src/resources/skills/react-best-practices/rules/js-hoist-regexp.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-hoist-regexp.md -->","src/resources/skills/react-best-practices/rules/js-index-maps.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-index-maps.md -->","src/resources/skills/react-best-practices/rules/js-length-check-first.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-length-check-first.md -->","src/resources/skills/react-best-practices/rules/js-min-max-loop.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-min-max-loop.md -->","src/resources/skills/react-best-practices/rules/js-set-map-lookups.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-set-map-lookups.md -->","src/resources/skills/react-best-practices/rules/js-tosorted-immutable.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-tosorted-immutable.md -->","src/resources/skills/react-best-practices/rules/rendering-activity.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-activity.md -->","src/resources/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-animate-svg-wrapper.md -->","src/resources/skills/react-best-practices/rules/rendering-conditional-render.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-conditional-render.md -->","src/resources/skills/react-best-practices/rules/rendering-content-visibility.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-content-visibility.md -->","src/resources/skills/react-best-practices/rules/rendering-hoist-jsx.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-hoist-jsx.md -->","src/resources/skills/react-best-practices/rules/rendering-hydration-no-flicker.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-hydration-no-flicker.md -->","src/resources/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-hydration-suppress-warning.md -->","src/resources/skills/react-best-practices/rules/rendering-svg-precision.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-svg-precision.md -->","src/resources/skills/react-best-practices/rules/rendering-usetransition-loading.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-usetransition-loading.md -->","src/resources/skills/react-best-practices/rules/rerender-defer-reads.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-defer-reads.md -->","src/resources/skills/react-best-practices/rules/rerender-dependencies.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-dependencies.md -->","src/resources/skills/react-best-practices/rules/rerender-derived-state-no-effect.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-derived-state-no-effect.md -->","src/resources/skills/react-best-practices/rules/rerender-derived-state.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-derived-state.md -->","src/resources/skills/react-best-practices/rules/rerender-functional-setstate.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-functional-setstate.md -->","src/resources/skills/react-best-practices/rules/rerender-lazy-state-init.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-lazy-state-init.md -->","src/resources/skills/react-best-practices/rules/rerender-memo-with-default-value.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-memo-with-default-value.md -->","src/resources/skills/react-best-practices/rules/rerender-memo.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-memo.md -->","src/resources/skills/react-best-practices/rules/rerender-move-effect-to-event.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-move-effect-to-event.md -->","src/resources/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-simple-expression-in-memo.md -->","src/resources/skills/react-best-practices/rules/rerender-transitions.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-transitions.md -->","src/resources/skills/react-best-practices/rules/rerender-use-ref-transient-values.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-use-ref-transient-values.md -->","src/resources/skills/react-best-practices/rules/server-after-nonblocking.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-after-nonblocking.md -->","src/resources/skills/react-best-practices/rules/server-auth-actions.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-auth-actions.md -->","src/resources/skills/react-best-practices/rules/server-cache-lru.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-cache-lru.md -->","src/resources/skills/react-best-practices/rules/server-cache-react.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-cache-react.md -->","src/resources/skills/react-best-practices/rules/server-dedup-props.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-dedup-props.md -->","src/resources/skills/react-best-practices/rules/server-parallel-fetching.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-parallel-fetching.md -->","src/resources/skills/react-best-practices/rules/server-serialization.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-serialization.md -->","src/resources/skills/review/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freview%2FSKILL.md -->","src/resources/skills/security-review/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fsecurity-review%2FSKILL.md -->","src/resources/skills/spike-wrap-up/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fspike-wrap-up%2FSKILL.md -->","src/resources/skills/tdd/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Ftdd%2FSKILL.md -->","src/resources/skills/test/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Ftest%2FSKILL.md -->","src/resources/skills/userinterface-wiki/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2FSKILL.md -->","src/resources/skills/userinterface-wiki/rules/_sections.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2F_sections.md -->","src/resources/skills/userinterface-wiki/rules/_template.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2F_template.md -->","src/resources/skills/userinterface-wiki/rules/a11y-reduced-motion-check.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fa11y-reduced-motion-check.md -->","src/resources/skills/userinterface-wiki/rules/a11y-toggle-setting.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fa11y-toggle-setting.md -->","src/resources/skills/userinterface-wiki/rules/a11y-visual-equivalent.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fa11y-visual-equivalent.md -->","src/resources/skills/userinterface-wiki/rules/a11y-volume-control.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fa11y-volume-control.md -->","src/resources/skills/userinterface-wiki/rules/appropriate-confirmations-only.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fappropriate-confirmations-only.md -->","src/resources/skills/userinterface-wiki/rules/appropriate-errors-warnings.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fappropriate-errors-warnings.md -->","src/resources/skills/userinterface-wiki/rules/appropriate-no-decorative.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fappropriate-no-decorative.md -->","src/resources/skills/userinterface-wiki/rules/appropriate-no-high-frequency.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fappropriate-no-high-frequency.md -->","src/resources/skills/userinterface-wiki/rules/appropriate-no-punishing.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fappropriate-no-punishing.md -->","src/resources/skills/userinterface-wiki/rules/container-callback-ref.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-callback-ref.md -->","src/resources/skills/userinterface-wiki/rules/container-guard-initial-zero.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-guard-initial-zero.md -->","src/resources/skills/userinterface-wiki/rules/container-no-excessive-use.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-no-excessive-use.md -->","src/resources/skills/userinterface-wiki/rules/container-overflow-hidden.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-overflow-hidden.md -->","src/resources/skills/userinterface-wiki/rules/container-transition-delay.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-transition-delay.md -->","src/resources/skills/userinterface-wiki/rules/container-two-div-pattern.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-two-div-pattern.md -->","src/resources/skills/userinterface-wiki/rules/container-use-resize-observer.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-use-resize-observer.md -->","src/resources/skills/userinterface-wiki/rules/context-cleanup-nodes.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontext-cleanup-nodes.md -->","src/resources/skills/userinterface-wiki/rules/context-resume-suspended.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontext-resume-suspended.md -->","src/resources/skills/userinterface-wiki/rules/context-reuse-single.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontext-reuse-single.md -->","src/resources/skills/userinterface-wiki/rules/design-filter-for-character.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fdesign-filter-for-character.md -->","src/resources/skills/userinterface-wiki/rules/design-noise-for-percussion.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fdesign-noise-for-percussion.md -->","src/resources/skills/userinterface-wiki/rules/design-oscillator-for-tonal.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fdesign-oscillator-for-tonal.md -->","src/resources/skills/userinterface-wiki/rules/duration-max-300ms.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fduration-max-300ms.md -->","src/resources/skills/userinterface-wiki/rules/duration-press-hover.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fduration-press-hover.md -->","src/resources/skills/userinterface-wiki/rules/duration-shorten-before-curve.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fduration-shorten-before-curve.md -->","src/resources/skills/userinterface-wiki/rules/duration-small-state.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fduration-small-state.md -->","src/resources/skills/userinterface-wiki/rules/easing-entrance-ease-out.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-entrance-ease-out.md -->","src/resources/skills/userinterface-wiki/rules/easing-exit-ease-in.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-exit-ease-in.md -->","src/resources/skills/userinterface-wiki/rules/easing-for-state-change.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-for-state-change.md -->","src/resources/skills/userinterface-wiki/rules/easing-linear-only-progress.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-linear-only-progress.md -->","src/resources/skills/userinterface-wiki/rules/easing-natural-decay.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-natural-decay.md -->","src/resources/skills/userinterface-wiki/rules/easing-no-linear-motion.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-no-linear-motion.md -->","src/resources/skills/userinterface-wiki/rules/easing-transition-ease-in-out.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-transition-ease-in-out.md -->","src/resources/skills/userinterface-wiki/rules/envelope-exponential-decay.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fenvelope-exponential-decay.md -->","src/resources/skills/userinterface-wiki/rules/envelope-no-zero-target.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fenvelope-no-zero-target.md -->","src/resources/skills/userinterface-wiki/rules/envelope-set-initial-value.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fenvelope-set-initial-value.md -->","src/resources/skills/userinterface-wiki/rules/exit-key-required.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fexit-key-required.md -->","src/resources/skills/userinterface-wiki/rules/exit-matches-initial.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fexit-matches-initial.md -->","src/resources/skills/userinterface-wiki/rules/exit-prop-required.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fexit-prop-required.md -->","src/resources/skills/userinterface-wiki/rules/exit-requires-wrapper.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fexit-requires-wrapper.md -->","src/resources/skills/userinterface-wiki/rules/impl-default-subtle.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fimpl-default-subtle.md -->","src/resources/skills/userinterface-wiki/rules/impl-preload-audio.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fimpl-preload-audio.md -->","src/resources/skills/userinterface-wiki/rules/impl-reset-current-time.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fimpl-reset-current-time.md -->","src/resources/skills/userinterface-wiki/rules/mode-pop-layout-for-lists.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmode-pop-layout-for-lists.md -->","src/resources/skills/userinterface-wiki/rules/mode-sync-layout-conflict.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmode-sync-layout-conflict.md -->","src/resources/skills/userinterface-wiki/rules/mode-wait-doubles-duration.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmode-wait-doubles-duration.md -->","src/resources/skills/userinterface-wiki/rules/morphing-aria-hidden.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-aria-hidden.md -->","src/resources/skills/userinterface-wiki/rules/morphing-consistent-viewbox.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-consistent-viewbox.md -->","src/resources/skills/userinterface-wiki/rules/morphing-group-variants.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-group-variants.md -->","src/resources/skills/userinterface-wiki/rules/morphing-jump-non-grouped.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-jump-non-grouped.md -->","src/resources/skills/userinterface-wiki/rules/morphing-reduced-motion.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-reduced-motion.md -->","src/resources/skills/userinterface-wiki/rules/morphing-spring-rotation.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-spring-rotation.md -->","src/resources/skills/userinterface-wiki/rules/morphing-strokelinecap-round.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-strokelinecap-round.md -->","src/resources/skills/userinterface-wiki/rules/morphing-three-lines.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-three-lines.md -->","src/resources/skills/userinterface-wiki/rules/morphing-use-collapsed.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-use-collapsed.md -->","src/resources/skills/userinterface-wiki/rules/native-backdrop-styling.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnative-backdrop-styling.md -->","src/resources/skills/userinterface-wiki/rules/native-placeholder-styling.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnative-placeholder-styling.md -->","src/resources/skills/userinterface-wiki/rules/native-selection-styling.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnative-selection-styling.md -->","src/resources/skills/userinterface-wiki/rules/nested-consistent-timing.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnested-consistent-timing.md -->","src/resources/skills/userinterface-wiki/rules/nested-propagate-required.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnested-propagate-required.md -->","src/resources/skills/userinterface-wiki/rules/none-context-menu-entrance.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnone-context-menu-entrance.md -->","src/resources/skills/userinterface-wiki/rules/none-high-frequency.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnone-high-frequency.md -->","src/resources/skills/userinterface-wiki/rules/none-keyboard-navigation.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnone-keyboard-navigation.md -->","src/resources/skills/userinterface-wiki/rules/param-click-duration.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fparam-click-duration.md -->","src/resources/skills/userinterface-wiki/rules/param-filter-frequency-range.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fparam-filter-frequency-range.md -->","src/resources/skills/userinterface-wiki/rules/param-q-value-range.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fparam-q-value-range.md -->","src/resources/skills/userinterface-wiki/rules/param-reasonable-gain.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fparam-reasonable-gain.md -->","src/resources/skills/userinterface-wiki/rules/physics-active-state.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fphysics-active-state.md -->","src/resources/skills/userinterface-wiki/rules/physics-no-excessive-stagger.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fphysics-no-excessive-stagger.md -->","src/resources/skills/userinterface-wiki/rules/physics-spring-for-overshoot.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fphysics-spring-for-overshoot.md -->","src/resources/skills/userinterface-wiki/rules/physics-subtle-deformation.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fphysics-subtle-deformation.md -->","src/resources/skills/userinterface-wiki/rules/prefetch-hit-slop.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-hit-slop.md -->","src/resources/skills/userinterface-wiki/rules/prefetch-keyboard-tab.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-keyboard-tab.md -->","src/resources/skills/userinterface-wiki/rules/prefetch-not-everything.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-not-everything.md -->","src/resources/skills/userinterface-wiki/rules/prefetch-touch-fallback.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-touch-fallback.md -->","src/resources/skills/userinterface-wiki/rules/prefetch-trajectory-over-hover.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-trajectory-over-hover.md -->","src/resources/skills/userinterface-wiki/rules/prefetch-use-selectively.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-use-selectively.md -->","src/resources/skills/userinterface-wiki/rules/presence-disable-interactions.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpresence-disable-interactions.md -->","src/resources/skills/userinterface-wiki/rules/presence-hook-in-child.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpresence-hook-in-child.md -->","src/resources/skills/userinterface-wiki/rules/presence-safe-to-remove.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpresence-safe-to-remove.md -->","src/resources/skills/userinterface-wiki/rules/pseudo-content-required.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-content-required.md -->","src/resources/skills/userinterface-wiki/rules/pseudo-first-line-styling.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-first-line-styling.md -->","src/resources/skills/userinterface-wiki/rules/pseudo-hit-target-expansion.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-hit-target-expansion.md -->","src/resources/skills/userinterface-wiki/rules/pseudo-marker-styling.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-marker-styling.md -->","src/resources/skills/userinterface-wiki/rules/pseudo-over-dom-node.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-over-dom-node.md -->","src/resources/skills/userinterface-wiki/rules/pseudo-position-relative-parent.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-position-relative-parent.md -->","src/resources/skills/userinterface-wiki/rules/pseudo-z-index-layering.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-z-index-layering.md -->","src/resources/skills/userinterface-wiki/rules/spring-for-gestures.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fspring-for-gestures.md -->","src/resources/skills/userinterface-wiki/rules/spring-for-interruptible.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fspring-for-interruptible.md -->","src/resources/skills/userinterface-wiki/rules/spring-params-balanced.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fspring-params-balanced.md -->","src/resources/skills/userinterface-wiki/rules/spring-preserves-velocity.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fspring-preserves-velocity.md -->","src/resources/skills/userinterface-wiki/rules/staging-dim-background.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fstaging-dim-background.md -->","src/resources/skills/userinterface-wiki/rules/staging-one-focal-point.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fstaging-one-focal-point.md -->","src/resources/skills/userinterface-wiki/rules/staging-z-index-hierarchy.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fstaging-z-index-hierarchy.md -->","src/resources/skills/userinterface-wiki/rules/timing-consistent.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftiming-consistent.md -->","src/resources/skills/userinterface-wiki/rules/timing-no-entrance-context-menu.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftiming-no-entrance-context-menu.md -->","src/resources/skills/userinterface-wiki/rules/timing-under-300ms.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftiming-under-300ms.md -->","src/resources/skills/userinterface-wiki/rules/transition-name-cleanup.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftransition-name-cleanup.md -->","src/resources/skills/userinterface-wiki/rules/transition-name-required.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftransition-name-required.md -->","src/resources/skills/userinterface-wiki/rules/transition-name-unique.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftransition-name-unique.md -->","src/resources/skills/userinterface-wiki/rules/transition-over-js-library.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftransition-over-js-library.md -->","src/resources/skills/userinterface-wiki/rules/transition-style-pseudo-elements.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftransition-style-pseudo-elements.md -->","src/resources/skills/userinterface-wiki/rules/type-antialiased-on-retina.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-antialiased-on-retina.md -->","src/resources/skills/userinterface-wiki/rules/type-disambiguation-stylistic-set.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-disambiguation-stylistic-set.md -->","src/resources/skills/userinterface-wiki/rules/type-font-display-swap.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-font-display-swap.md -->","src/resources/skills/userinterface-wiki/rules/type-justify-with-hyphens.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-justify-with-hyphens.md -->","src/resources/skills/userinterface-wiki/rules/type-letter-spacing-uppercase.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-letter-spacing-uppercase.md -->","src/resources/skills/userinterface-wiki/rules/type-no-font-synthesis.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-no-font-synthesis.md -->","src/resources/skills/userinterface-wiki/rules/type-oldstyle-nums-for-prose.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-oldstyle-nums-for-prose.md -->","src/resources/skills/userinterface-wiki/rules/type-opentype-contextual-alternates.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-opentype-contextual-alternates.md -->","src/resources/skills/userinterface-wiki/rules/type-optical-sizing-auto.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-optical-sizing-auto.md -->","src/resources/skills/userinterface-wiki/rules/type-proper-fractions.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-proper-fractions.md -->","src/resources/skills/userinterface-wiki/rules/type-slashed-zero.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-slashed-zero.md -->","src/resources/skills/userinterface-wiki/rules/type-tabular-nums-for-data.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-tabular-nums-for-data.md -->","src/resources/skills/userinterface-wiki/rules/type-text-wrap-balance-headings.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-text-wrap-balance-headings.md -->","src/resources/skills/userinterface-wiki/rules/type-text-wrap-pretty.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-text-wrap-pretty.md -->","src/resources/skills/userinterface-wiki/rules/type-underline-offset.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-underline-offset.md -->","src/resources/skills/userinterface-wiki/rules/type-variable-weight-continuous.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-variable-weight-continuous.md -->","src/resources/skills/userinterface-wiki/rules/ux-aesthetic-usability.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-aesthetic-usability.md -->","src/resources/skills/userinterface-wiki/rules/ux-cognitive-load-reduce.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-cognitive-load-reduce.md -->","src/resources/skills/userinterface-wiki/rules/ux-common-region-boundaries.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-common-region-boundaries.md -->","src/resources/skills/userinterface-wiki/rules/ux-doherty-perceived-speed.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-doherty-perceived-speed.md -->","src/resources/skills/userinterface-wiki/rules/ux-doherty-under-400ms.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-doherty-under-400ms.md -->","src/resources/skills/userinterface-wiki/rules/ux-fitts-hit-area.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-fitts-hit-area.md -->","src/resources/skills/userinterface-wiki/rules/ux-fitts-target-size.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-fitts-target-size.md -->","src/resources/skills/userinterface-wiki/rules/ux-goal-gradient-progress.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-goal-gradient-progress.md -->","src/resources/skills/userinterface-wiki/rules/ux-hicks-minimize-choices.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-hicks-minimize-choices.md -->","src/resources/skills/userinterface-wiki/rules/ux-jakobs-familiar-patterns.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-jakobs-familiar-patterns.md -->","src/resources/skills/userinterface-wiki/rules/ux-millers-chunking.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-millers-chunking.md -->","src/resources/skills/userinterface-wiki/rules/ux-pareto-prioritize-features.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-pareto-prioritize-features.md -->","src/resources/skills/userinterface-wiki/rules/ux-peak-end-finish-strong.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-peak-end-finish-strong.md -->","src/resources/skills/userinterface-wiki/rules/ux-postels-accept-messy-input.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-postels-accept-messy-input.md -->","src/resources/skills/userinterface-wiki/rules/ux-pragnanz-simplify.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-pragnanz-simplify.md -->","src/resources/skills/userinterface-wiki/rules/ux-progressive-disclosure.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-progressive-disclosure.md -->","src/resources/skills/userinterface-wiki/rules/ux-proximity-grouping.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-proximity-grouping.md -->","src/resources/skills/userinterface-wiki/rules/ux-serial-position.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-serial-position.md -->","src/resources/skills/userinterface-wiki/rules/ux-similarity-consistency.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-similarity-consistency.md -->","src/resources/skills/userinterface-wiki/rules/ux-teslers-complexity.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-teslers-complexity.md -->","src/resources/skills/userinterface-wiki/rules/ux-uniform-connectedness.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-uniform-connectedness.md -->","src/resources/skills/userinterface-wiki/rules/ux-von-restorff-emphasis.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-von-restorff-emphasis.md -->","src/resources/skills/userinterface-wiki/rules/ux-zeigarnik-show-incomplete.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-zeigarnik-show-incomplete.md -->","src/resources/skills/userinterface-wiki/rules/visual-animate-shadow-pseudo.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-animate-shadow-pseudo.md -->","src/resources/skills/userinterface-wiki/rules/visual-border-alpha-colors.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-border-alpha-colors.md -->","src/resources/skills/userinterface-wiki/rules/visual-button-shadow-anatomy.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-button-shadow-anatomy.md -->","src/resources/skills/userinterface-wiki/rules/visual-concentric-radius.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-concentric-radius.md -->","src/resources/skills/userinterface-wiki/rules/visual-consistent-spacing-scale.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-consistent-spacing-scale.md -->","src/resources/skills/userinterface-wiki/rules/visual-layered-shadows.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-layered-shadows.md -->","src/resources/skills/userinterface-wiki/rules/visual-no-pure-black-shadow.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-no-pure-black-shadow.md -->","src/resources/skills/userinterface-wiki/rules/visual-shadow-direction.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-shadow-direction.md -->","src/resources/skills/userinterface-wiki/rules/visual-shadow-matches-elevation.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-shadow-matches-elevation.md -->","src/resources/skills/userinterface-wiki/rules/weight-duration-matches-action.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fweight-duration-matches-action.md -->","src/resources/skills/userinterface-wiki/rules/weight-match-action.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fweight-match-action.md -->","src/resources/skills/verify-before-complete/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fverify-before-complete%2FSKILL.md -->","src/resources/skills/web-design-guidelines/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fweb-design-guidelines%2FSKILL.md -->","src/resources/skills/web-quality-audit/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fweb-quality-audit%2FSKILL.md -->","src/resources/skills/write-docs/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fwrite-docs%2FSKILL.md -->","src/resources/skills/write-milestone-brief/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fwrite-milestone-brief%2FSKILL.md -->"},"files":{"docs/agents/domain.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=docs%2Fagents%2Fdomain.md -->","docs/agents/issue-tracker.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=docs%2Fagents%2Fissue-tracker.md -->","docs/agents/triage-labels.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=docs%2Fagents%2Ftriage-labels.md -->","gsd-orchestrator/SKILL.md":"---\nname: gsd-orchestrator\ndescription: >\n  Build software products autonomously via GSD headless mode. Handles the full\n  lifecycle: write a spec, launch a build, poll for completion, handle blockers,\n  track costs, and verify the result. Use when asked to \"build something\",\n  \"create a project\", \"run gsd\", \"check build status\", or any task that\n  requires autonomous software development via subprocess.\nmetadata:\n  openclaw:\n    requires:\n      bins: [gsd]\n    install:\n      kind: node\n      package: gsd-pi\n      bins: [gsd]\n---\n\n<objective>\nYou are an autonomous agent that builds software by orchestrating GSD as a subprocess.\nGSD is a headless CLI that plans, codes, tests, and ships software from a spec.\nYou control it via shell commands, exit codes, and JSON output — no SDK, no RPC.\n</objective>\n\n<mental_model>\nGSD headless is a subprocess you launch and monitor. Think of it like a junior developer\nyou hand a spec to:\n\n1. You write the spec (what to build)\n2. You launch the build (`gsd headless ... new-milestone --context spec.md --auto`)\n3. You wait for it to finish (exit code tells you the outcome)\n4. You check the result (query state, inspect files, verify deliverables)\n5. If blocked, you intervene (steer, supply answers, or escalate)\n\nThe subprocess handles all planning, coding, testing, and git commits internally.\nYou never write application code yourself — GSD does that.\n</mental_model>\n\n<critical_rules>\n- **Flags before command.** `gsd headless [--flags] [command] [args]`. Flags after the command are ignored.\n- **Redirect stderr.** JSON output goes to stdout. Progress goes to stderr. Always `2>/dev/null` when parsing JSON.\n- **Check exit codes.** 0=success, 1=error, 10=blocked (needs you), 11=cancelled.\n- **Use `query` to poll.** Instant (~50ms), no LLM cost. Use it between steps, not `auto` for status.\n- **Budget awareness.** Track `cost.total` from query results. Set limits before launching long runs.\n- **One project directory per build.** Each GSD project needs its own directory with a `.gsd/` folder.\n</critical_rules>\n\n<routing>\nRoute based on what you need to do:\n\n**Build something from scratch:**\nRead `workflows/build-from-spec.md` — write spec, init directory, launch, monitor, verify.\n\n**Check on a running or completed build:**\nRead `workflows/monitor-and-poll.md` — query state, interpret phases, handle blockers.\n\n**Execute with fine-grained control:**\nRead `workflows/step-by-step.md` — run one unit at a time with decision points.\n\n**Understand the JSON output:**\nRead `references/json-result.md` — field reference for HeadlessJsonResult.\n\n**Pre-supply answers or secrets:**\nRead `references/answer-injection.md` — answer file schema and injection mechanism.\n\n**Look up a specific command:**\nRead `references/commands.md` — full command reference with flags and examples.\n</routing>\n\n<quick_reference>\n\n**Launch a full build (spec to working code):**\n```bash\nmkdir -p /tmp/my-project && cd /tmp/my-project && git init\ncat > spec.md << 'EOF'\n# Your Product Spec Here\nBuild a ...\nEOF\ngsd headless --output-format json --context spec.md new-milestone --auto 2>/dev/null\n```\n\n**Check project state (instant, free):**\n```bash\ncd /path/to/project\ngsd headless query | jq '{phase: .state.phase, progress: .state.progress, cost: .cost.total}'\n```\n\n**Resume work on an existing project:**\n```bash\ncd /path/to/project\ngsd headless --output-format json auto 2>/dev/null\n```\n\n**Run one step at a time:**\n```bash\nRESULT=$(gsd headless --output-format json next 2>/dev/null)\necho \"$RESULT\" | jq '{status: .status, phase: .phase, cost: .cost.total}'\n```\n\n</quick_reference>\n\n<exit_codes>\n| Code | Meaning | Your action |\n|------|---------|-------------|\n| `0`  | Success | Check deliverables, verify output, report completion |\n| `1`  | Error or timeout | Inspect stderr, check `.gsd/STATE.md`, retry or escalate |\n| `10` | Blocked | Query state for blocker details, steer around it or escalate to human |\n| `11` | Cancelled | Process was interrupted — resume with `--resume <sessionId>` or restart |\n</exit_codes>\n\n<project_structure>\nGSD creates and manages all state in `.gsd/`:\n```\n.gsd/\n  PROJECT.md          # What this project is\n  REQUIREMENTS.md     # Capability contract\n  DECISIONS.md        # Architectural decisions (append-only)\n  KNOWLEDGE.md        # Persistent project knowledge (manual rules, memory-projected patterns/lessons)\n  STATE.md            # Current phase and next action\n  milestones/\n    M001-xxxxx/\n      M001-xxxxx-CONTEXT.md    # Scope, constraints, assumptions\n      M001-xxxxx-ROADMAP.md    # Slices with checkboxes\n      M001-xxxxx-SUMMARY.md    # Completion summary\n      slices/S01/\n        S01-PLAN.md            # Tasks\n        S01-SUMMARY.md         # Slice summary\n        tasks/\n          T01-PLAN.md          # Individual task spec\n          T01-SUMMARY.md       # Task completion summary\n```\n\nState is derived from files on disk — checkboxes in ROADMAP.md and PLAN.md are the source of truth for completion. You never need to edit these files. GSD manages them. But you can read them to understand progress.\n</project_structure>\n\n<flags>\n| Flag | Description |\n|------|-------------|\n| `--output-format <fmt>` | `text` (default), `json` (structured result at exit), `stream-json` (JSONL events) |\n| `--json` | Alias for `--output-format stream-json` — JSONL event stream to stdout |\n| `--bare` | Skip CLAUDE.md, AGENTS.md, user settings, user skills. Use for CI/ecosystem runs. |\n| `--resume <id>` | Resume a prior headless session by its session ID |\n| `--timeout N` | Overall timeout in ms (default: 300000, use 0 to disable) |\n| `--model ID` | Override LLM model |\n| `--supervised` | Forward interactive UI requests to orchestrator via stdout/stdin |\n| `--response-timeout N` | Timeout (ms) for orchestrator response in supervised mode (default: 30000) |\n| `--answers <path>` | Pre-supply answers and secrets from JSON file |\n| `--events <types>` | Filter JSONL to specific event types (comma-separated, implies `--json`) |\n| `--verbose` | Show tool calls in progress output |\n| `--context <path>` | Spec file path for `new-milestone` (use `-` for stdin) |\n| `--context-text <text>` | Inline spec text for `new-milestone` |\n| `--auto` | Chain into auto-mode after `new-milestone` |\n</flags>\n\n<answer_injection>\nPre-supply answers and secrets for fully autonomous runs:\n\n```bash\ngsd headless --answers answers.json --output-format json auto 2>/dev/null\n```\n\n```json\n{\n  \"questions\": { \"question_id\": \"selected_option\" },\n  \"secrets\": { \"API_KEY\": \"sk-...\" },\n  \"defaults\": { \"strategy\": \"first_option\" }\n}\n```\n\n- **questions** — question ID to answer (string for single-select, string[] for multi-select)\n- **secrets** — env var to value, injected into child process environment\n- **defaults.strategy** — `\"first_option\"` (default) or `\"cancel\"` for unmatched questions\n\nSee `references/answer-injection.md` for the full mechanism.\n</answer_injection>\n\n<event_streaming>\nFor real-time monitoring, use JSONL event streaming:\n\n```bash\ngsd headless --json auto 2>/dev/null | while read -r line; do\n  TYPE=$(echo \"$line\" | jq -r '.type')\n  case \"$TYPE\" in\n    tool_execution_start) echo \"Tool: $(echo \"$line\" | jq -r '.toolName')\" ;;\n    extension_ui_request) echo \"GSD: $(echo \"$line\" | jq -r '.message // .title // empty')\" ;;\n    agent_end) echo \"Session ended\" ;;\n  esac\ndone\n```\n\nFilter to specific events: `--events agent_end,execution_complete,extension_ui_request`\n\nAvailable types: `agent_start`, `agent_end`, `tool_execution_start`, `tool_execution_end`,\n`tool_execution_update`, `extension_ui_request`, `message_start`, `message_end`,\n`message_update`, `turn_start`, `turn_end`, `cost_update`, `execution_complete`.\n</event_streaming>\n\n<all_commands>\n| Command | Purpose |\n|---------|---------|\n| `auto` | Run all queued units until milestone complete or blocked (default) |\n| `next` | Run exactly one unit, then exit |\n| `query` | Instant JSON snapshot — state, next dispatch, costs (no LLM, ~50ms) |\n| `new-milestone` | Create milestone from spec file |\n| `dispatch <phase>` | Force specific phase (research, plan, execute, complete, reassess, uat, replan) |\n| `stop` / `pause` | Control auto-mode |\n| `steer <desc>` | Hard-steer plan mid-execution |\n| `skip` / `undo` | Unit control |\n| `queue` | Queue/reorder milestones |\n| `history` | View execution history |\n| `doctor` | Health check + auto-fix |\n| `knowledge <rule\\|pattern\\|lesson>` | Add persistent project knowledge |\n\nSee `references/commands.md` for the complete reference.\n</all_commands>\n","packages/mcp-server/README.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=packages%2Fmcp-server%2FREADME.md -->","packages/rpc-client/README.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=packages%2Frpc-client%2FREADME.md -->","src/resources/extensions/gsd/docs/COORDINATION.md":"# Auto-mode coordination is single-host\n\nThe DB-backed coordination tables introduced by Phase B (`workers`,\n`milestone_leases`, `unit_dispatches`, `cancellation_requests`,\n`command_queue`) and the supporting `runtime_kv` table from Phase C all\nrely on **shared SQLite WAL on local disk**. They do not work across\nmachines.\n\n## Why single-host only\n\n- SQLite WAL coordination — the locking primitives that make\n  `claimMilestoneLease`, `recordDispatchClaim`, and `claimNextCommand`\n  atomic — is local-disk only. Network filesystems (NFS, SMB, S3FS) and\n  fuse mounts break the lock semantics that the WAL relies on.\n- Heartbeat TTL (`workers.last_heartbeat_at`) compares timestamps written\n  with SQLite wall-clock time (`datetime('now')`). Across machines without\n  wall-clock synchronization (for example NTP/chrony), TTL filtering can\n  produce phantom-active or premature-crashed verdicts. Monotonic clocks\n  are not used for these comparisons.\n- Fencing tokens (`milestone_leases.fencing_token`) are monotonically\n  ordered by SQL within a single transaction. Cross-host races could\n  produce duplicate tokens if two SQLite processes opened the same DB\n  on a network mount.\n\n## What does work\n\n- Multiple `gsd auto` worker processes on the **same machine**, sharing\n  the project's SQLite DB via WAL. The lease check refuses concurrent\n  claims on the same milestone; the dispatch ledger's partial unique\n  index refuses double-claims of the same unit.\n- A single `gsd auto` worker plus arbitrary read-only consumers\n  (dashboards, doctors) on the same machine.\n- Worktree-based parallelism on the same machine, where each worker\n  holds a different milestone lease.\n\n## Multi-host alternatives\n\nIf you need to coordinate `gsd auto` workers across machines, you need\na real coordinator: Postgres for the ledger + a leader-election service\n(etcd, Consul) for the leases. That's out of scope for these phases.\nThe schema and module shapes here would need a non-trivial backend\nswap before they could ride on top of either.\n","src/resources/extensions/gsd/docs/claude-marketplace-import.md":"# Claude Marketplace Import\n\nThis document describes the Claude marketplace import feature in GSD: what it reads, what it imports, what it persists, and what it does not translate into active GSD/Pi runtime behavior.\n\n---\n\n## What this feature does\n\nGSD can read Claude Code marketplace catalogs, inspect the plugins they reference, and import selected Claude skills into GSD/Pi while preserving Claude-style namespace identity.\n\nThe interactive entry point is:\n\n```text\n/gsd prefs import-claude\n```\n\nYou can also choose scope explicitly:\n\n```text\n/gsd prefs import-claude global\n/gsd prefs import-claude project\n```\n\n---\n\n## Claude Code model this feature follows\n\nAnthropic documents Claude marketplaces as sources users add with:\n\n```text\n/plugin marketplace add <github repo or local path>\n```\n\nA marketplace contains a catalog at:\n\n```text\n.claude-plugin/marketplace.json\n```\n\nAnthropic distinguishes between:\n\n- **Marketplace source** — where Claude fetches `marketplace.json`\n- **Plugin source** — where Claude fetches each plugin listed in that marketplace\n- **Installed plugin cache** — Claude copies installed plugin payloads into:\n\n```text\n~/.claude/plugins/cache\n```\n\nAnthropic also documents user-added marketplace sources under:\n\n```text\n~/.claude/plugins/marketplaces\n```\n\nGSD aligns its Claude import flow to that model.\n\n---\n\n## Where GSD looks\n\nFor Claude plugin and marketplace material, GSD prefers Claude-managed locations first:\n\n1. `~/.claude/plugins/marketplaces`\n2. `~/.claude/plugins/cache`\n3. `~/.claude/plugins`\n\nAfter that, GSD still allows local clone-style convenience paths such as sibling repos or `~/repos/...` paths. Those fallbacks remain supported for developer workflows, but they are not the primary Claude storage model.\n\n---\n\n## What GSD imports\n\n### Imported into GSD/Pi settings\n\n- Claude skills discovered directly from configured skill roots\n- Marketplace-derived skills\n\nImported marketplace skills preserve canonical namespace identity, for example:\n\n```text\npython3-development:stinkysnake\nscientific-method:experiment-protocol\n```\n\n### Discovered, modeled, and validated\n\n- Marketplace-derived agents\n\n### Discovered but not translated into active Pi-native runtime behavior\n\n- hooks\n- MCP server definitions\n- LSP server definitions\n- other plugin metadata that does not currently map directly into active GSD/Pi runtime surfaces\n\n---\n\n## Import flow\n\nThe import flow does the following:\n\n1. discover Claude skills and marketplace/plugin roots\n2. identify marketplace roots by checking for `.claude-plugin/marketplace.json`\n3. inspect discovered plugins and inventory their components\n4. let you select components to import\n5. validate the selection for canonical conflicts and ambiguity\n6. persist imported resources into GSD/Pi settings\n\n---\n\n## Namespace behavior\n\nGSD preserves Claude plugin namespace semantics rather than flattening plugin components into anonymous global names.\n\n### Canonical references\n\nCanonical references remain available for imported components:\n\n- skills: `plugin-name:skill-name`\n- agents: `plugin-name:agent-name`\n\n### Shorthand\n\nGSD supports shorthand lookup when it is unambiguous.\n\n### Local-first resolution\n\nWhen a namespaced component refers to another component by bare name, GSD tries the same plugin namespace first before broader lookup.\n\n---\n\n## Important safeguard: marketplace agent directories are not stored as package sources\n\nClaude plugin agent directories are markdown agent-definition directories, for example:\n\n```text\n.../plugins/python3-development/agents\n```\n\nGSD does **not** persist imported marketplace agent directories into:\n\n```json\nsettings.packages\n```\n\nThis is intentional.\n\n### Why\n\nPersisting an `.../agents` directory into `settings.packages` can cause Pi startup to treat that directory as an extension/package root. In real host validation, that produced extension loader failures such as:\n\n```text\nCannot find module '.../agents'\n```\n\nGSD now avoids writing those entries.\n\n---\n\n## Settings effects\n\n### Skills\n\nImported skills are persisted into Pi skill settings. Depending on the selection path, they may also be added to GSD preferences.\n\n### Marketplace agents\n\nMarketplace agents remain part of the import model and validation surface, but their `agents/` directories are not persisted as package roots.\n\n---\n\n## Diagnostics\n\nGSD distinguishes between:\n\n- **canonical conflicts** — hard errors\n- **shorthand overlaps** — warnings when canonical names remain distinct\n- **alias conflicts** — diagnostics for alias collisions or shadowing\n\nThis allows imported marketplace content to be validated without reporting valid overlap as fatal breakage.\n\n---\n\n## Verification status of this feature\n\nThis feature has been verified in three ways:\n\n1. **Contract/unit tests** for parsing, namespacing, resolution, diagnostics, and import behavior\n2. **Portable integration-style tests** using local or cloned marketplace fixtures\n3. **Real host validation** against the installed `gsd` binary and actual Claude-managed directories on the host machine\n\nReal host validation included:\n\n- clean startup of the installed `gsd` binary after fixing stale bad settings\n- successful invocation of an imported skill (`/stinkysnake`)\n- successful execution of `/gsd prefs import-claude global`\n- verification that imported marketplace agent directories were **not** reintroduced into `settings.packages`\n\n---\n\n## Current limitations\n\n- GSD does not yet translate every Claude plugin component type into active Pi-native runtime behavior\n- marketplace-derived agents are not persisted as package roots, by design\n- clone-style local fallbacks still exist for developer convenience, even though Claude-managed marketplace/plugin locations are preferred first\n\n---\n\n## References\n\n- Anthropic: Claude Code settings\n- Anthropic: Create and distribute a plugin marketplace\n- Anthropic: Plugins and plugin reference\n","src/resources/extensions/gsd/docs/preferences-reference.md":"# GSD Preferences Reference\n\nFull documentation for `~/.gsd/PREFERENCES.md` (global) and `.gsd/PREFERENCES.md` (project).\n\n---\n\n## Notes\n\n- Keep this skill-first.\n- Prefer explicit skill names or absolute paths.\n- Use absolute paths for personal/local skills when you want zero ambiguity.\n- These preferences guide which skills GSD should load and follow; they do not override higher-priority instructions in the current conversation.\n- For Claude marketplace/plugin import behavior, see `~/.gsd/agent/extensions/gsd/docs/claude-marketplace-import.md`.\n\n---\n\n## Semantics\n\n### Empty Arrays vs Omitted Fields\n\n**Empty arrays (`[]`) are equivalent to omitting the field entirely.** During validation, GSD deletes empty arrays from the preferences object (see `validatePreferences()` in `preferences.ts`):\n\n```typescript\nfor (const key of [\n  \"always_use_skills\",\n  \"prefer_skills\",\n  \"avoid_skills\",\n  \"custom_instructions\",\n] as const) {\n  if (validated[key] && validated[key]!.length === 0) {\n    delete validated[key];\n  }\n}\n```\n\nThese are functionally identical:\n\n```yaml\n# Explicit empty arrays — will be normalized away\nprefer_skills: []\navoid_skills: []\nskill_rules: []\n\n# Omitted entirely — same result\n# (just don't write these fields)\n```\n\n**Recommendation:** Omit fields you don't need. Empty arrays add noise with no effect.\n\n### Global vs Project Preferences\n\nPreferences are loaded from two locations and merged:\n\n1. **Global:** `~/.gsd/PREFERENCES.md` — applies to all projects\n2. **Project:** `.gsd/PREFERENCES.md` — applies to the current project only\n\n**Merge behavior** (see `mergePreferences()` in `preferences.ts`):\n\n- **Scalar fields** (`skill_discovery`, `budget_ceiling`, etc.): Project wins if defined, otherwise global. Uses nullish coalescing (`??`).\n- **Array fields** (`always_use_skills`, `prefer_skills`, etc.): Concatenated via `mergeStringLists()` (global first, then project).\n- **Object fields** (`models`, `git`, `auto_supervisor`): Shallow merge via spread operator `{ ...base, ...override }`.\n\nFor `models`, project settings override global at the phase level. If global has `planning: opus` and project has `planning: sonnet`, the project wins. But if project omits `research`, global's `research` setting is preserved.\n\n### Skill Discovery vs Skill Preferences\n\nThese are **separate concerns**:\n\n| Field                                                | What it controls                                          | Code reference                                           |\n| ---------------------------------------------------- | --------------------------------------------------------- | -------------------------------------------------------- |\n| `skill_discovery`                                    | **Whether** GSD looks for relevant skills during research | `resolveSkillDiscoveryMode()` in `preferences.ts`        |\n| `always_use_skills`, `prefer_skills`, `avoid_skills` | **Which** skills to use when they're found relevant       | `renderPreferencesForSystemPrompt()` in `preferences.ts` |\n\nSetting `prefer_skills: []` does **not** disable skill discovery — it just means you have no preference overrides. Use `skill_discovery: off` to disable discovery entirely.\n\n---\n\n## Field Guide\n\n- `version`: schema version. Start at `1`.\n\n- `mode`: workflow mode — `\"solo\"` or `\"team\"`. Sets sensible defaults for git and project settings based on your workflow. Mode defaults are the lowest priority layer — any explicit preference overrides them. Omit to configure everything manually.\n\n  | Setting                | `solo`       | `team`       |\n  | ---------------------- | ------------ | ------------ |\n  | `git.auto_push`        | `true`       | `false`      |\n  | `git.push_branches`    | `false`      | `true`       |\n  | `git.pre_merge_check`  | `false`      | `true`       |\n  | `git.merge_strategy`   | `\"squash\"`   | `\"squash\"`   |\n  | `git.isolation`        | `\"none\"`     | `\"none\"`     |\n  | `unique_milestone_ids` | `false`      | `true`       |\n\n  Quick setup: `/gsd mode` (global) or `/gsd mode project` (project-level).\n\n- `always_use_skills`: skills GSD should use whenever they are relevant.\n\n- `prefer_skills`: soft defaults GSD should prefer when relevant.\n\n- `avoid_skills`: skills GSD should avoid unless clearly needed.\n\n- `skill_rules`: situational rules with a human-readable `when` trigger and one or more of `use`, `prefer`, or `avoid`.\n\n- `custom_instructions`: extra durable instructions related to skill use. For operational project knowledge, use `.gsd/KNOWLEDGE.md` instead. Rules are file-canonical; patterns and lessons are persisted to the `memories` table and projected back into `KNOWLEDGE.md` on the next session start.\n\n- `language`: preferred response language for all GSD interactions. Accepts any language name or code — `\"Chinese\"`, `\"zh\"`, `\"German\"`, `\"de\"`, `\"日本語\"`, etc. When set, GSD injects \"Always respond in \\<language\\>\" into every agent's system prompt, including after `/clear`. Quickest way to set it: `/gsd language <name>`. To clear: `/gsd language off`.\n\n- `models`: per-stage model selection (applies to both auto-mode and guided-flow dispatches). Keys: `research`, `planning`, `discuss`, `execution`, `execution_simple`, `completion`, `validation`, `subagent`. Values can be:\n  - Simple string: `\"claude-sonnet-4-6\"` — single model, no fallbacks\n  - Provider-qualified string: `\"bedrock/claude-sonnet-4-6\"` — targets a specific provider when the same model ID exists across multiple providers\n  - Object with fallbacks: `{ model: \"claude-opus-4-6\", fallbacks: [\"glm-5\", \"minimax-m2.5\"] }` — tries fallbacks in order if primary fails\n  - Object with provider: `{ model: \"claude-opus-4-6\", provider: \"bedrock\" }` — explicit provider targeting in object format\n  - Omit a key to use whatever model is currently active (except `discuss` and `validation` which fall back to `planning` when unset). Fallbacks are tried when model switching fails (provider unavailable, rate limited, etc.).\n  - `discuss` — used for milestone/slice discussion (interactive context gathering). Falls back to `planning` if unset.\n  - `validation` — used for gate evaluation, roadmap reassessment, milestone validation, and doc rewrites. Falls back to `planning` if unset.\n\n- `skill_staleness_days`: number — skills unused for this many days get deprioritized during discovery. Set to `0` to disable staleness tracking. Default: `60`.\n\n- `skill_discovery`: controls how GSD discovers and applies skills during auto-mode. Valid values:\n  - `auto` — skills are found and applied automatically without prompting.\n  - `suggest` — (default) skills are identified during research but not installed automatically.\n  - `off` — skill discovery is disabled entirely.\n\n- `auto_supervisor`: configures the auto-mode supervisor that monitors agent progress and enforces timeouts. Keys:\n  - `model`: model ID to use for the supervisor process (defaults to the currently active model).\n  - `soft_timeout_minutes`: minutes before the supervisor issues a soft warning (default: 20).\n  - `idle_timeout_minutes`: minutes of inactivity before the supervisor intervenes (default: 10).\n  - `hard_timeout_minutes`: minutes before the supervisor forces termination (default: 30).\n\n- `min_request_interval_ms`: number — minimum integer milliseconds between auto-mode LLM request dispatches. Non-integer values are rounded down (e.g., `1000.9 → 1000`). Use this to proactively slow auto-mode on rate-limited providers and reduce 429 errors. Set to `0` to disable. Default: `0` (disabled).\n\n- `git`: configures GSD's git behavior. All fields are optional — omit any to use defaults. Keys:\n  - `auto_push`: boolean — automatically push commits to the remote after committing. Default: `false`.\n  - `push_branches`: boolean — push the milestone branch to the remote after commits. Default: `false`.\n  - `remote`: string — git remote name to push to. Default: `\"origin\"`.\n  - `snapshots`: boolean — create WIP snapshot commits (e.g. pre-dispatch and stale-uncommitted-changes safety commits emitted by the doctor). Set to `false` to suppress all doctor-initiated `gsd snapshot:` commits. Default: `true`.\n  - `pre_merge_check`: boolean or `\"auto\"` — run pre-merge checks before merging a worktree back to the integration branch. `true` always runs, `false` never runs, `\"auto\"` runs when CI is detected. Default: `\"auto\"`.\n  - `commit_type`: string — override the conventional commit type prefix. Must be one of: `feat`, `fix`, `refactor`, `docs`, `test`, `chore`, `perf`, `ci`, `build`, `style`. Default: inferred from diff content.\n  - `main_branch`: string — the primary branch name for new git repos (e.g., `\"main\"`, `\"master\"`, `\"trunk\"`). Also used by `getMainBranch()` as the preferred branch when auto-detection is ambiguous. Default: `\"main\"`.\n  - `merge_strategy`: `\"squash\"` or `\"merge\"` — controls how worktree branches are merged back. `\"squash\"` combines all commits into one; `\"merge\"` preserves individual commits. Default: `\"squash\"`.\n  - `isolation`: `\"none\"`, `\"worktree\"`, or `\"branch\"` — controls auto-mode git isolation strategy. `\"none\"` works directly on the current branch with no worktree or milestone branch (default, ideal for step-mode with hot reloads); `\"worktree\"` creates a milestone worktree for isolated work; `\"branch\"` works directly in the project root but creates a milestone branch (useful for submodule-heavy repos). `worktree` requires a committed `HEAD`; in a zero-commit repo, GSD temporarily treats it as `none` until the first commit exists. Default: `\"none\"`.\n  - `manage_gitignore`: boolean — when `false`, GSD will not touch `.gitignore` at all. Useful when your project has a strictly managed `.gitignore` and you don't want GSD adding entries. Default: `true`.\n  - `worktree_post_create`: string — script to run after a worktree is created (both auto-mode and manual `/worktree`). Receives `SOURCE_DIR` and `WORKTREE_DIR` as environment variables. Can be absolute or relative to project root. Runs with 30-second timeout. Failure is non-fatal (logged as warning). Default: none.\n  - `auto_pr`: boolean — automatically create a GitHub pull request after a milestone branch is merged. Requires `gh` CLI to be installed. Default: `false`.\n  - `pr_target_branch`: string — branch to target when `auto_pr` is enabled. Defaults to `main_branch` when omitted.\n  - **Deprecated:** `commit_docs` — no longer valid; `.gsd/` is always gitignored. Remove this setting.\n  - **Deprecated:** `merge_to_main` — no longer valid; milestone-level merge is always used. Remove this setting.\n\n- `workspace`: configures multi-repository parent workspaces. Keys:\n  - `mode`: `\"project\"` (default single-repo behavior) or `\"parent\"` (one `.gsd` controlling child repos).\n  - `repositories`: object map of repository IDs to config.\n    - Repository ID format: `^[A-Za-z0-9][A-Za-z0-9._-]*$`.\n    - Reserved ID: `project` is implicit and always maps to the project root; user-defined `workspace.repositories.project` is rejected.\n    - `path`: required relative path that must resolve within the project root (paths escaping via `..` are rejected).\n    - `role`: optional short description of what the repo owns.\n    - `verification`: optional array of verification commands for that repo.\n    - `commit_policy`: optional `\"auto\"` or `\"skip\"` to include or skip commit actions per repo.\n\n## Workspace Example\n\n```yaml\n---\nversion: 1\nworkspace:\n  mode: parent\n  repositories:\n    frontend:\n      path: frontend\n      role: web UI\n      verification:\n        - npm test\n        - npm run lint\n      commit_policy: auto\n    backend:\n      path: ./backend\n      role: API server\n      verification:\n        - go test ./...\n      commit_policy: auto\n---\n```\n\nThis config sets a parent workspace with two child repositories. The implicit `project` repository is always created for the project root and cannot be user-defined.\n\n- `unique_milestone_ids`: boolean — when `true`, generates milestone IDs in `M{seq}-{rand6}` format (e.g. `M001-eh88as`) instead of plain sequential `M001`. Prevents ID collisions in team workflows where multiple contributors create milestones concurrently. Both formats coexist — existing `M001`-style milestones remain valid. Default: `false`.\n\n- `budget_ceiling`: number — maximum dollar amount to spend on auto-mode. When reached, behavior is controlled by `budget_enforcement`. Default: no limit.\n\n- `budget_enforcement`: `\"warn\"`, `\"pause\"`, or `\"halt\"` — action taken when `budget_ceiling` is reached.\n  - `warn` — log a warning but continue execution.\n  - `pause` — pause auto-mode and wait for user confirmation.\n  - `halt` — stop auto-mode immediately.\n  - Default: `\"pause\"`.\n\n- `context_pause_threshold`: number (`0` or `1-100`) — live context window usage percentage at which auto-mode should pause to suggest checkpointing. Set to `0` to disable. Use whole percentages like `75`, not fractional ratios like `0.75`. Default: `0` (disabled).\n\n- `token_profile`: `\"budget\"`, `\"balanced\"`, `\"quality\"`, or `\"burn-max\"` — coordinates model selection, phase skipping, and context compression. `budget` skips research/reassessment and uses cheaper models; `balanced` (default) skips research/reassessment to reduce token burn; `quality` prefers higher-quality models; `burn-max` keeps full-context defaults, disables downgrade routing, and keeps phase skips off.\n\n- `planning_depth`: `\"light\"` or `\"deep\"` — controls project-level discovery before milestone planning. `\"light\"` is the default milestone discussion flow. `\"deep\"` runs workflow preferences, project discussion, requirements discussion, a research-decision gate, and optional project research before milestone planning. Enable it with `/gsd new-project --deep`, `/gsd new-milestone --deep`, or by setting `planning_depth: deep` in project-local `.gsd/PREFERENCES.md`. Global `~/.gsd/PREFERENCES.md` does not opt every fresh repo into deep mode. Deep mode writes `.gsd/PROJECT.md`, `.gsd/REQUIREMENTS.md`, `.gsd/runtime/research-decision.json`, and, when research is approved, `.gsd/research/STACK.md`, `FEATURES.md`, `ARCHITECTURE.md`, and `PITFALLS.md`.\n\n- `phases`: fine-grained control over which phases run. Usually set by `token_profile`, but can be overridden. Keys:\n  - `skip_research`: boolean — skip milestone-level research. Default: `false`.\n  - `reassess_after_slice`: boolean — run a dedicated roadmap-reassessment unit after each completed slice. Default: `false` (per ADR-003 §4). The plan-slice agent for the next slice performs JIT reassessment via a prompt preamble at zero additional token cost; a dedicated reassess session is opt-in. Set to `true` (e.g. via the `burn-max` profile) if you want the explicit session.\n  - `skip_reassess`: boolean — force-disable roadmap reassessment even if `reassess_after_slice` is enabled. Default: `false`.\n  - `skip_slice_research`: boolean — skip per-slice research. Default: `false`.\n\n- `reactive_execution`: controls automatic parallel task dispatch inside a slice. Reactive execution is enabled by default when omitted; set `enabled: false` to opt out. With default-on behavior, GSD only attempts a reactive batch when at least three ready tasks are available and the task-plan IO graph is non-ambiguous. If you set `enabled: true` explicitly, GSD uses the earlier opt-in threshold of two ready tasks. Keys:\n  - `enabled`: boolean — set `false` to force sequential task execution. Default: `true`.\n  - `max_parallel`: number — maximum tasks to dispatch in one batch, range `1`-`8`. Default: `2`.\n  - `isolation_mode`: `\"same-tree\"` — currently the only supported value.\n  - `subagent_model`: string — optional model override for reactive task subagents. Falls back to the `models.subagent` routing when omitted.\n\n- `remote_questions`: route interactive questions to Slack/Discord for headless auto-mode. Keys:\n  - `channel`: `\"slack\"` or `\"discord\"` — channel type.\n  - `channel_id`: string or number — channel ID.\n  - `timeout_minutes`: number — question timeout in minutes (clamped 1-30).\n  - `poll_interval_seconds`: number — poll interval in seconds (clamped 2-30).\n\n- `notifications`: configures desktop notification behavior during auto-mode. Keys:\n  - `enabled`: boolean — master toggle for all notifications. Default: `true`.\n  - `on_complete`: boolean — notify when a unit completes. Default: `true`.\n  - `on_error`: boolean — notify on errors. Default: `true`.\n  - `on_budget`: boolean — notify when budget thresholds are reached. Default: `true`.\n  - `on_milestone`: boolean — notify when a milestone finishes. Default: `true`.\n  - `on_attention`: boolean — notify when manual attention is needed. Default: `true`.\n  - Terminal auto-loop errors persist an `activity/*-auto-crash-note.json` file with error/session metadata; when available, the error notification includes the crash-note path and instructs resuming with `/gsd auto`.\n\n- `cmux`: configures cmux terminal integration when GSD is running inside a cmux workspace. Keys:\n  - `enabled`: boolean — master toggle for cmux integration. Default: `false`.\n  - `notifications`: boolean — route desktop notifications through cmux. Default: `true` when enabled.\n  - `sidebar`: boolean — publish status, progress, and log metadata to the cmux sidebar. Default: `true` when enabled.\n  - `splits`: boolean — run supported subagent work in visible cmux splits. Default: `false`.\n  - `browser`: boolean — reserve the future browser integration flag. Default: `false`.\n\n- `dynamic_routing`: configures the dynamic model router that adjusts model selection based on task complexity. Keys:\n  - `enabled`: boolean — enable dynamic routing. Default: `false`.\n  - `tier_models`: object — model overrides per complexity tier. Keys: `light`, `standard`, `heavy`. Values are model ID strings.\n  - `escalate_on_failure`: boolean — escalate to a higher-tier model when the current one fails. Default: `true`.\n  - `budget_pressure`: boolean — downgrade model tier when budget is under pressure. Default: `true`.\n  - `cross_provider`: boolean — allow routing across different providers. Default: `true`.\n  - `hooks`: boolean — enable routing hooks. Default: `true`.\n  - `capability_routing`: boolean — enable capability-profile scoring for model selection within a tier. Requires `enabled: true`. Default: `false`.\n\n- `disabled_model_providers`: string[] — provider IDs to hide from model selection and routing (for example `[\"google-gemini-cli\"]`). This only affects model availability (`/model`, auto-model selection, routing); it does not disable tool auth flows like `google_search`.\n\n- `uok`: Unified Orchestration Kernel controls. Keys:\n  - `enabled`: boolean — enable kernel wrappers and contract observers. Default: `true`.\n  - `legacy_fallback.enabled`: boolean — emergency release fallback that forces legacy orchestration behavior even when `uok.enabled` is `true`. Default: `false`.\n    - Runtime override: set `GSD_UOK_FORCE_LEGACY=1` (or `GSD_UOK_LEGACY_FALLBACK=1`) to force legacy behavior for the current process.\n  - `gates.enabled`: boolean — route checks through the unified gate runner and persist `gate_runs`. Default: `true`.\n  - `model_policy.enabled`: boolean — enforce policy filtering before model capability scoring. Default: `true`.\n  - `execution_graph.enabled`: boolean — enable DAG scheduler facade/adapters for execution. Default: `true`.\n  - `gitops.enabled`: boolean — persist turn-level git transaction records. Default: `true`.\n  - `gitops.turn_action`: `\"commit\"` | `\"snapshot\"` | `\"status-only\"` — turn transaction mode. Default: `\"commit\"` (per-task atomic commits).\n  - `gitops.turn_push`: boolean — whether turn transactions should include push intent metadata. Default: `false`.\n  - `audit_unified.enabled`: boolean — dual-write unified audit envelope events. Default: `true`.\n  - `plan_v2.enabled`: boolean — enable bounded clarify/research/draft/compile planning flow. Default: `true`.\n\n- `context_management`: configures context hygiene for auto-mode sessions. Keys:\n  - `observation_masking`: boolean — mask old tool results to reduce context bloat. Default: `true`.\n  - `observation_mask_turns`: number — keep this many recent turns verbatim (1-50). Default: `8`.\n  - `compaction_threshold_percent`: number — trigger compaction at this % of context window (0.5-0.95). Lower values fire compaction earlier, reducing drift. Default: `0.60`.\n  - `tool_result_max_chars`: number — max chars per tool result in GSD sessions (200-10000). Default: `800`.\n\n- `auto_visualize`: boolean — show a visualizer hint after each milestone completion in auto-mode. Default: `false`.\n\n- `auto_report`: boolean — generate an HTML report snapshot after each milestone completion. Default: `true`.\n\n- `search_provider`: `\"brave\"`, `\"tavily\"`, `\"ollama\"`, `\"native\"`, or `\"auto\"` — selects the search backend for research phases. `\"native\"` forces Anthropic's built-in web search only; provider values force that backend and disable native search; `\"auto\"` uses the default heuristic. Default: `\"auto\"`.\n\n- `context_selection`: `\"full\"` or `\"smart\"` — controls how files are inlined into context. `\"full\"` inlines entire files; `\"smart\"` uses semantic chunking to include only the most relevant sections. Default is derived from `token_profile`.\n\n- `parallel`: configures parallel orchestration for running multiple slices concurrently. Keys:\n  - `enabled`: boolean — enable parallel execution. Default: `false`.\n  - `max_workers`: number — maximum concurrent workers (1-4). Default: `2`.\n  - `budget_ceiling`: number — optional per-parallel-run budget ceiling.\n  - `merge_strategy`: `\"per-slice\"` or `\"per-milestone\"` — when to merge worktree results back. Default: `\"per-milestone\"`.\n  - `auto_merge`: `\"auto\"`, `\"confirm\"`, or `\"manual\"` — merge behavior after completion. `\"auto\"` merges immediately; `\"confirm\"` asks first; `\"manual\"` leaves branches for you. Default: `\"confirm\"`.\n  - `worker_model`: string — optional model override for parallel milestone workers. When set, workers use this model (e.g. `\"claude-haiku-4-5\"`) instead of inheriting the coordinator's model. Useful for cost savings on execution-heavy milestones.\n\n- `workspace`: repository-scoping for parent/multi-repo workspaces. Keys:\n  - `mode`: `\"project\"` | `\"parent\"` — enables single-repo (default) or parent workspace behavior.\n  - `repositories`: map of repository IDs to repository config:\n    - `path`: string (required) — path relative to project root.\n    - `role`: string (optional) — informational role label.\n    - `verification`: string[] (optional) — repository-specific verification commands used when global `verification_commands` is not set.\n    - `commit_policy`: `\"auto\"` | `\"skip\"` (optional) — per-repository closeout commit behavior.\n  - `project` is always an implicit repository target mapped to the project root for backward compatibility.\n  - Plan/task `targetRepositories` defaults to `[\"project\"]` when omitted.\n\n- `verification_commands`: string[] — shell commands to run as verification after task execution (e.g., `[\"npm test\", \"npm run lint\"]`). Commands run in order; if any fails, the task is marked as needing fixes.\n\n- `verification_auto_fix`: boolean — when `true`, automatically attempt to fix verification failures instead of just reporting them. Default: `false`.\n\n- `verification_max_retries`: number — maximum number of fix-and-retry cycles for verification failures. Default: `0` (no retries).\n\n- `per_unit_cost_cap_usd`: number — per-unit retry cost ceiling in USD for verification retries. Must be a positive finite number when set; invalid values are rejected during preference validation. Default: `5.0`. During auto-verification and artifact-retry flows, auto-mode pauses when the current unit reaches this cap or when current unit cost spikes to at least `3.0x` the rolling average.\n\n- `uat_dispatch`: boolean — when `true`, enables UAT (User Acceptance Testing) dispatch mode. Default: `false`.\n\n- `post_unit_hooks`: array — hooks that fire after a unit completes. Each entry has:\n  - `name`: string — unique hook identifier.\n  - `after`: string[] — unit types that trigger this hook (e.g., `[\"execute-task\"]`).\n  - `prompt`: string — prompt sent to the LLM. Supports `{milestoneId}`, `{sliceId}`, `{taskId}` substitutions.\n  - `max_cycles`: number — max times this hook fires per trigger (default: 1, max: 10).\n  - `model`: string — optional model override.\n  - `artifact`: string — expected output file name (relative to task/slice dir). Hook is skipped if file already exists (idempotent).\n  - `retry_on`: string — if this file is produced instead of the artifact, re-run the trigger unit then re-run hooks.\n  - `agent`: string — agent definition file to use for hook execution.\n  - `enabled`: boolean — toggle without removing (default: `true`).\n\n- `pre_dispatch_hooks`: array — hooks that fire before a unit is dispatched. Each entry has:\n  - `name`: string — unique hook identifier.\n  - `before`: string[] — unit types to intercept.\n  - `action`: `\"modify\"`, `\"skip\"`, or `\"replace\"` — what to do with the unit.\n  - `prepend`: string — text prepended to unit prompt (for `\"modify\"` action).\n  - `append`: string — text appended to unit prompt (for `\"modify\"` action).\n  - `prompt`: string — replacement prompt (for `\"replace\"` action; required when action is `\"replace\"`).\n  - `unit_type`: string — override unit type label (for `\"replace\"` action).\n  - `skip_if`: string — for `\"skip\"` action: only skip if this file exists (relative to unit dir).\n  - `model`: string — optional model override when this hook fires.\n  - `enabled`: boolean — toggle without removing (default: `true`).\n\n  **Action validation:**\n  - `\"modify\"` requires at least one of `prepend` or `append`.\n  - `\"replace\"` requires `prompt`.\n  - `\"skip\"` is valid with no additional fields.\n\n  **Known unit types for `before`/`after`:** `research-milestone`, `plan-milestone`, `research-slice`, `plan-slice`, `execute-task`, `complete-slice`, `replan-slice`, `reassess-roadmap`, `run-uat`.\n\n- `experimental`: opt-in experimental features. All features here are **off by default** — you must explicitly set each one to `true` to enable it. Features in this block may change or be removed without a deprecation cycle while in experimental status. Keys:\n  - `rtk`: boolean — enable RTK (Real-Time Kompression) shell-command compression. When enabled, GSD wraps shell commands through the RTK binary to reduce token usage during command execution. RTK is downloaded automatically on first use if not already installed. **Default: `false`** (opt-in required). Set `GSD_RTK_DISABLED=1` in the environment to force-disable regardless of this preference.\n\n---\n\n## Best Practices\n\n- Keep `always_use_skills` short.\n- Use `skill_rules` for situational routing, not broad personality preferences.\n- Prefer skill names for stable built-in skills.\n- Prefer absolute paths for local personal skills.\n- **Omit fields you don't need** — empty arrays add noise with no effect.\n\n---\n\n## Workflow Mode Examples\n\n**Solo developer — auto-push, simple IDs:**\n\n```yaml\n---\nversion: 1\nmode: solo\n---\n```\n\nEquivalent to setting `git.auto_push: true`, `git.push_branches: false`, `git.pre_merge_check: false`, `git.merge_strategy: squash`, `git.isolation: none`, `unique_milestone_ids: false`.\n\n**Team — unique IDs, push branches, pre-merge checks:**\n\n```yaml\n---\nversion: 1\nmode: team\n---\n```\n\nEquivalent to setting `git.auto_push: false`, `git.push_branches: true`, `git.pre_merge_check: true`, `git.merge_strategy: squash`, `git.isolation: none`, `unique_milestone_ids: true`.\n\n**Mode with overrides — team mode but with auto-push:**\n\n```yaml\n---\nversion: 1\nmode: team\ngit:\n  auto_push: true\n---\n```\n\nGets all team defaults except `auto_push`, which is explicitly overridden to `true`. Any explicit setting always wins over the mode default.\n\n---\n\n## Minimal Example\n\nThe cleanest preferences file only specifies what you actually want:\n\n```yaml\n---\nversion: 1\nalways_use_skills:\n  - debug-like-expert\nskill_discovery: suggest\nmodels:\n  planning: claude-opus-4-6\n  execution: claude-sonnet-4-6\n---\n```\n\nEverything else uses defaults. No `prefer_skills: []`, no `avoid_skills: []`, no `auto_supervisor: {}` — those are just noise.\n\n---\n\n## Models Example\n\n```yaml\n---\nversion: 1\nmodels:\n  research: claude-sonnet-4-6\n  planning: claude-opus-4-6\n  execution: claude-sonnet-4-6\n  completion: claude-sonnet-4-6\n---\n```\n\nOpus for planning (where architectural decisions matter most), Sonnet for everything else (faster, cheaper). Omit any key to use the currently selected model.\n\n## Models with Fallbacks Example\n\n```yaml\n---\nversion: 1\nmodels:\n  research:\n    model: openrouter/deepseek/deepseek-r1\n    fallbacks:\n      - openrouter/minimax/minimax-m2.5\n  planning:\n    model: claude-opus-4-6\n    fallbacks:\n      - openrouter/z-ai/glm-5\n      - openrouter/moonshotai/kimi-k2.5\n  execution:\n    model: openrouter/z-ai/glm-5\n    fallbacks:\n      - openrouter/minimax/minimax-m2.5\n  completion: openrouter/minimax/minimax-m2.5\n---\n```\n\nWhen a model fails to switch (provider unavailable, rate limited, credits exhausted), GSD automatically tries the next model in the `fallbacks` list. This ensures auto-mode continues even when your preferred provider hits limits.\n\n## Provider Targeting\n\nWhen the same model ID exists across multiple providers (e.g., `claude-sonnet-4-6` on both Anthropic and Bedrock), use the `provider/model` format or the `provider` field to target a specific one:\n\n```yaml\n---\nversion: 1\nmodels:\n  # String format: provider/model\n  research: bedrock/claude-sonnet-4-6\n  planning: anthropic/claude-opus-4-6\n\n  # Object format: explicit provider field\n  execution:\n    model: claude-sonnet-4-6\n    provider: bedrock\n    fallbacks:\n      - anthropic/claude-sonnet-4-6\n---\n```\n\nIf you use a bare model ID (no provider prefix) and it exists in multiple providers, GSD will warn you and resolve to the first available match. Use `provider/model` format to avoid ambiguity.\n\n**Cost-optimized example** — use cheap models with expensive ones as fallback for critical phases:\n\n```yaml\n---\nversion: 1\nmodels:\n  research: openrouter/deepseek/deepseek-r1 # $0.28/$0.42 per 1M tokens\n  planning:\n    model: claude-opus-4-6 # $5/$25 — best for architecture\n    fallbacks:\n      - openrouter/z-ai/glm-5 # $1/$3.20 — strong alternative\n  execution: openrouter/minimax/minimax-m2.5 # $0.30/$1.20 — cheapest quality\n  completion: openrouter/minimax/minimax-m2.5\n---\n```\n\n---\n\n## Example Variations\n\n**Minimal — always load a UAT skill and route Clerk tasks:**\n\n```yaml\n---\nversion: 1\nalways_use_skills:\n  - /Users/you/.claude/skills/verify-uat\nskill_rules:\n  - when: finishing implementation and human judgment matters\n    use:\n      - /Users/you/.claude/skills/verify-uat\n---\n```\n\n**Richer routing — prefer cleanup and authentication skills:**\n\n```yaml\n---\nversion: 1\nprefer_skills:\n  - commit-ignore\nskill_rules:\n  - when: task involves Clerk authentication\n    use:\n      - clerk\n      - clerk-setup\n  - when: the user is looking for installable capability rather than implementation\n    prefer:\n      - find-skills\n---\n```\n\n---\n\n## Git Preferences Example\n\n```yaml\n---\nversion: 1\ngit:\n  auto_push: true\n  push_branches: true\n  remote: origin\n  snapshots: true\n  pre_merge_check: auto\n  commit_type: feat\n---\n```\n\nAll git fields are optional. Omit any field to use the default behavior. Project-level preferences override global preferences on a per-field basis.\n\n---\n\n## Budget & Cost Control Example\n\n```yaml\n---\nversion: 1\nbudget_ceiling: 10.00\nbudget_enforcement: pause\ncontext_pause_threshold: 80\n---\n```\n\nSets a $10 budget ceiling. Auto-mode pauses when the ceiling is reached. Context window pauses at 80% usage for checkpointing.\n\n---\n\n## Notifications Example\n\n```yaml\n---\nversion: 1\nnotifications:\n  enabled: true\n  on_complete: false\n  on_error: true\n  on_budget: true\n  on_milestone: true\n  on_attention: true\n---\n```\n\nDisables per-unit completion notifications (noisy in long runs) while keeping error, budget, milestone, and attention notifications enabled.\n\n---\n\n## cmux Example\n\n```yaml\n---\nversion: 1\ncmux:\n  enabled: true\n  notifications: true\n  sidebar: true\n  splits: true\n  browser: false\n---\n```\n\nEnables cmux-aware notifications, sidebar metadata, and visible subagent splits when GSD is running inside a cmux terminal.\n\n---\n\n## Post-Unit Hooks Example\n\n```yaml\n---\nversion: 1\npost_unit_hooks:\n  - name: code-review\n    after:\n      - execute-task\n    prompt: \"Review the code changes in {sliceId}/{taskId} for quality, security, and test coverage.\"\n    max_cycles: 1\n    artifact: REVIEW.md\n---\n```\n\nRuns an automated code review after each task execution. Skips if `REVIEW.md` already exists (idempotent).\n\n---\n\n## Pre-Dispatch Hooks Examples\n\n**Modify — inject instructions before every task:**\n\n```yaml\n---\nversion: 1\npre_dispatch_hooks:\n  - name: enforce-standards\n    before:\n      - execute-task\n    action: modify\n    prepend: \"Follow our TypeScript coding standards and always run linting.\"\n---\n```\n\n**Skip — skip per-slice research when a research file already exists:**\n\n```yaml\n---\nversion: 1\npre_dispatch_hooks:\n  - name: skip-existing-research\n    before:\n      - research-slice\n    action: skip\n    skip_if: RESEARCH.md\n---\n```\n\n**Replace — substitute a custom prompt for task execution:**\n\n```yaml\n---\nversion: 1\npre_dispatch_hooks:\n  - name: tdd-execute\n    before:\n      - execute-task\n    action: replace\n    prompt: \"Implement the task using strict TDD. Write failing tests first, then implement, then refactor.\"\n    model: claude-opus-4-6\n---\n```\n\n---\n\n## Token Profile & Phases Example\n\n```yaml\n---\nversion: 1\ntoken_profile: budget\nphases:\n  skip_research: true\n  skip_reassess: true\n  skip_slice_research: false\n---\n```\n\nUses the `budget` profile to minimize token usage, with explicit override to keep slice-level research enabled.\n\n---\n\n## Remote Questions Example\n\n```yaml\n---\nversion: 1\nremote_questions:\n  channel: slack\n  channel_id: \"C0123456789\"\n  timeout_minutes: 15\n  poll_interval_seconds: 10\n---\n```\n\nRoutes interactive questions to a Slack channel for headless auto-mode sessions. Questions time out after 15 minutes if unanswered.\n\n---\n\n## Dynamic Routing Example\n\n```yaml\n---\nversion: 1\ndynamic_routing:\n  enabled: true\n  tier_models:\n    light: openrouter/minimax/minimax-m2.5\n    standard: claude-sonnet-4-6\n    heavy: claude-opus-4-6\n  escalate_on_failure: true\n  budget_pressure: true\n---\n```\n\nAutomatically selects model tier based on task complexity. Simple tasks use the `light` model, complex tasks escalate to `heavy`. Under budget pressure, tasks are routed to cheaper tiers.\n\n---\n\n## Parallel Execution Example\n\n```yaml\n---\nversion: 1\nparallel:\n  enabled: true\n  max_workers: 3\n  merge_strategy: per-milestone\n  auto_merge: confirm\n---\n```\n\nRuns up to 3 slices concurrently in separate worktrees. Results are merged per-milestone with user confirmation.\n\n---\n\n## Verification Example\n\n```yaml\n---\nversion: 1\nverification_commands:\n  - npm test\n  - npm run lint\n  - npm run typecheck\nverification_auto_fix: true\nverification_max_retries: 2\n---\n```\n\nRuns test, lint, and typecheck after each task. On failure, auto-fix is attempted up to 2 times before reporting the issue.\n\n## Experimental Features Example\n\n```yaml\n---\nversion: 1\nexperimental:\n  rtk: true\n---\n```\n\nOpts in to RTK shell-command compression. RTK is downloaded automatically on first use. Set `GSD_RTK_DISABLED=1` to force-disable at the environment level regardless of this setting.\n","src/resources/extensions/gsd/prompts/heal-skill.md":"## Skill Heal Analysis\n\nAnalyze the just-completed unit ({{unitId}}) for skill drift.\n\n### Steps\n\n1. **Identify loaded skill**: Check which SKILL.md file was read during this unit by examining recent tool calls. If no skill was explicitly loaded (no `read` call to a SKILL.md path), write \"No skill loaded — skipping heal analysis\" to {{healArtifact}} and stop.\n\n2. **Read the skill**: Load the SKILL.md that was used during this unit.\n\n3. **Compare execution to skill guidance**: Review what the agent actually did vs what the skill recommended. Look for:\n   - API patterns the skill recommended that the agent did differently\n   - Error handling approaches the skill specified but the agent bypassed\n   - Conventions the skill documented that the agent ignored\n   - Outdated instructions in the skill that caused errors, retries, or workarounds\n   - Commands or tools the skill referenced that no longer exist or have changed\n\n4. **Assess drift severity**:\n   - **None**: Agent followed skill correctly → write \"No drift detected\" to {{healArtifact}} and stop\n   - **Minor**: Agent found a better approach but skill isn't wrong → append a note to `.gsd/KNOWLEDGE.md` and stop\n   - **Significant**: Skill has outdated or incorrect guidance → continue to step 5\n\n5. **If significant drift found**, append a heal suggestion to `.gsd/skill-review-queue.md`:\n\n```markdown\n### {{skillName}} (flagged {{date}})\n- **Unit:** {{unitId}}\n- **Issue:** {1-2 sentence description of what was wrong}\n- **Root cause:** {outdated API / incorrect pattern / missing context / etc.}\n- **Discovery method:** {how the agent discovered the skill was wrong — error message, trial and error, docs lookup, etc.}\n- **Proposed fix:**\n  - File: {relative path to the file in the skill directory}\n  - Section: {section heading or line range}\n  - Current: {quote the incorrect/outdated text}\n  - Suggested: {the corrected text}\n- **Action:** [ ] Reviewed [ ] Updated [ ] Dismissed\n```\n\nThen write a brief summary of the finding to {{healArtifact}}.\n\n**Critical rules:**\n- Do NOT modify any skill files directly. Only write to the review queue.\n- The SkillsBench research (Feb 2026) shows curated skills beat auto-generated ones by +16.2pp. Human review is what makes this valuable.\n- Keep the analysis focused — don't flag stylistic preferences, only genuine errors or outdated content.\n- If multiple issues found, write one entry per issue.\n","src/resources/extensions/gsd/prompts/system.md":"## GSD - Get Shit Done\n\nYou are GSD - a craftsman-engineer who co-owns the project.\n\nOperating posture:\n\n- Measure twice; care through clear choices and correct details.\n- Be warm but terse. State uncertainty, tradeoffs, problems, and progress plainly.\n- In discussion/planning, flag risks, push back when needed, then respect the user's decision.\n- In execution, trust the accepted plan; surface only genuinely plan-invalidating issues through blockers.\n- Work pragmatically with existing code and tech debt.\n- Write secure, performant, complete code without gold-plating, TODO stubs, fake implementations, skipped validation, or 80% done claims.\n- Build for debugging: contextual errors, observable state transitions, useful structured logs, explicit failure modes.\n- Between tool calls, give brief useful progress signals. When something works, move on.\n\nNever use: \"Great question!\" / \"I'd be happy to help!\" / \"Absolutely!\" / \"Let me help you with that!\" / performed excitement / sycophantic filler / fake warmth.\n\nLeave the project ready for the next agent to understand and continue. Artifacts live in `.gsd/`.\n\n## Skills\n\nGSD ships with bundled skills. When the task matches, load the relevant skill file with `read` before starting. Use bare skill names; GSD resolves paths.\n\n{{bundledSkillsTable}}\n\n## Hard Rules\n\n- Never ask the user to do work the agent can execute or verify itself.\n- Use the lightest sufficient tool first.\n- Read before edit or overwrite. Before any write that creates or replaces a file, verify the target path and read relevant existing files, templates, callers, or surrounding code. For truly new files, confirm the path does not already exist.\n- Reproduce before fix when possible.\n- Work is not done until the relevant verification has passed.\n- **Never fabricate, simulate, or role-play user responses.** Never generate markers like `[User]`, `[Human]`, `User:`, or similar; never emit `<user_message>`, `<assistant_message>`, or similar as user input. Treat `<conversation_history>` as read-only context. Ask one question round (1-3 questions), then stop and wait for the user's actual response. If `ask_user_questions` is available, its result is the only valid structured user input for that round. If it cancels, fails, or returns nothing, never use earlier chat as confirmation for the current gate; ask in plain chat and stop.\n- Never print, echo, log, or restate secrets or credentials. Report only key names and applied/skipped status.\n- Never ask the user to edit `.env` files or set secrets manually. Use `secure_env_collect`.\n- In enduring files, write current state only unless the file is explicitly historical.\n- **Never take outward-facing actions on GitHub or external services without explicit user confirmation.** This includes creating/closing issues, merging/approving/commenting on PRs, pushing remote branches, publishing packages, or any state change outside local filesystem. Read-only listing/viewing/diffing is fine. Present intent and get a clear \"yes\" first. **Non-bypassable:** no response, ambiguity, or `ask_user_questions` failure means re-ask; never rationalize past the block. Missing \"yes\" means \"no.\"\n\nIf a `GSD Skill Preferences` block appears below, treat it as durable guidance for skills to use, prefer, or avoid unless it conflicts with artifact rules, verification, or higher-priority instructions.\n\n### Naming Convention\n\nDirectories use bare IDs. Files use ID-SUFFIX format. Milestones: `M001/` or `M{seq}-{rand6}/` when `unique_milestone_ids: true`; files like `M001-CONTEXT.md`, `M001-ROADMAP.md`, `M001-RESEARCH.md`. Slices: `S01/` with `S01-PLAN.md`, `S01-RESEARCH.md`, `S01-SUMMARY.md`, `S01-UAT.md`. Tasks: `T01-PLAN.md`, `T01-SUMMARY.md`. Titles live inside content, not names.\n\n### Directory Structure\n\n```\n.gsd/\n  PROJECT.md, REQUIREMENTS.md, DECISIONS.md, KNOWLEDGE.md, CODEBASE.md, OVERRIDES.md, QUEUE.md, STATE.md\n  runtime/, activity/, worktrees/\n  milestones/M001/\n    M001-CONTEXT.md, M001-RESEARCH.md, M001-ROADMAP.md, M001-SUMMARY.md\n    slices/S01/\n      S01-CONTEXT.md, S01-RESEARCH.md, S01-PLAN.md, S01-SUMMARY.md, S01-UAT.md\n      tasks/T01-PLAN.md, tasks/T01-SUMMARY.md\n```\n\n`runtime/`, `activity/`, `worktrees/`, and `STATE.md` are system-managed. `PROJECT.md` is current state; `REQUIREMENTS.md` is the active capability contract; `DECISIONS.md` and `KNOWLEDGE.md` are append-only; `CODEBASE.md` is an auto-refreshed codebase map.\n\n### Isolation Model\n\nAuto-mode isolation is configured in `.gsd/PREFERENCES.md` under `git.isolation`: **none** works on the current branch; **worktree** uses `.gsd/worktrees/<MID>/` on `milestone/<MID>` and merges back on completion; **branch** uses `milestone/<MID>` in-place. Slices commit sequentially on the active branch; no per-slice branches.\n\n**If you are executing in auto-mode, your working directory is shown in the Working Directory section of your prompt.** Use relative paths. Do not navigate to any other copy of the project.\n\n### Conventions\n\n- `PROJECT.md`: living current-state doc, refreshed at slice completion when stale.\n- `REQUIREMENTS.md`: capability contract; requirements move Active/Validated/Deferred/Blocked/Out of Scope as evidence changes.\n- `DECISIONS.md` and `KNOWLEDGE.md`: append-only decision/rule registers.\n- `CODEBASE.md`: generated structural cache. GSD auto-refreshes it when tracked files change and injects it when available. Use `/gsd codebase update` only to force refresh.\n- `CONTEXT.md`: milestone/slice scope, goals, constraints, decisions; authoritative when present.\n- Milestones are phases; slices are demoable increments ordered by risk; tasks are single-context units.\n- Checkboxes are toggled by gsd_* tools, never manually.\n- Summaries compress prior work; read them instead of all task details.\n\n### Artifact Templates\n\nTemplates are in `{{templatesDir}}`.\n\n**Always read the relevant template before writing an artifact.** Parsers depend on exact formatting:\n\n- Roadmap slices: `- [ ] **S01: Title** \\`risk:level\\` \\`depends:[]\\``\n- Plan tasks: `- [ ] **T01: Title** \\`est:estimate\\``\n- Summaries use YAML frontmatter\n\n### Commands\n\n- `/gsd` - contextual wizard\n- `/gsd auto` - auto-execute (fresh context per task)\n- `/gsd stop` - stop auto-mode\n- `/gsd status` - progress dashboard overlay\n- `/gsd queue` - queue future milestones (safe while auto-mode is running)\n- `/gsd quick <task>` - quick task with GSD guarantees (atomic commits, state tracking) but no milestone ceremony\n- `/gsd codebase [generate|update|stats]` - manage the `.gsd/CODEBASE.md` cache used for prompt context\n- `{{shortcutDashboard}}` - toggle dashboard overlay\n- `{{shortcutShell}}` - show shell processes\n\n## Execution Heuristics\n\n### Tool rules\n\n**File reading:** Use `read` for file inspection. Never use `cat`, `head`, `tail`, or `sed -n` to view contents. Use `read` with `offset`/`limit` for slicing. `bash` is for searching (`rg`, `grep`, `find`) and commands, not displaying files.\n\n**File editing:** Always `read` before `edit` or overwrite. Before `write`, confirm whether the path exists; if it does, `read` it first and preserve intentional existing content. Use `write` only for new files or complete rewrites.\n\n**Code navigation:** Use `lsp` for definition, type_definition, implementation, references, calls, hover, signature, symbols, rename, code_actions, format, and diagnostics. Do not `grep` symbol definitions or shell out to formatters when `lsp` can do it. After code edits, run `lsp diagnostics`.\n\n**Codebase exploration:** Use `subagent` with `scout` for broad unfamiliar subsystem mapping, `rg` for text search, and `lsp` for structure. Do not read files one-by-one to explore; search first, then read relevant files.\n\n**Documentation lookup:** Use `resolve_library` -> `get_library_docs` for library/framework questions. Start with `tokens=5000`. Never guess API signatures when docs are available.\n\n**External facts:** Use `search-the-web` + `fetch_page`, or `search_and_read`; use `freshness` for recency. Never state current facts from training data without verification.\n\n**Background processes:** Use `bg_shell` `start` + `wait_for_ready` for servers/watchers/daemons. Never use `bash` with `&` or `nohup`; inherited stdout can hang. Never poll with `sleep`; use `wait_for_ready`. For status use `digest`, `highlights` for significant lines, and `output` only when debugging.\n\n**One-shot commands:** Use `async_bash` for builds, tests, and installs. Results are pushed on exit; use `await_job` only to block on a specific job.\n\n**Stale job hygiene:** After editing source to fix a failure, `cancel_job` every in-flight `async_bash` job before rerunning. Changed inputs make in-flight outputs untrusted.\n\n**Secrets:** Use `secure_env_collect`. Never ask the user to edit `.env` files or paste secrets.\n\n**Browser verification:** Verify frontend work against a running app. Discovery: `browser_find`/`browser_snapshot_refs`. Action: refs/selectors -> `browser_batch`. Verification: `browser_assert`. Diagnostics: `browser_diff` -> console/network logs -> full inspection as last resort. Retry only with a new hypothesis.\n\n### Anti-patterns — never do these\n\n- Never use `cat` to read a file you might edit; use `read`.\n- Never `grep` for a function definition when `lsp` go-to-definition is available.\n- Never poll servers with `sleep` loops; use `bg_shell wait_for_ready`.\n- Never background with `bash` + `&`; use `bg_shell start`.\n- Never use `bg_shell output` for status; use `digest`.\n- Never read files one-by-one to understand a subsystem; use `rg` or `scout` first.\n- Never guess library APIs; use `get_library_docs`.\n- Never ask the user to run/check/set something you can do.\n- Never await stale async jobs after editing source; cancel then re-run.\n- Never query `.gsd/gsd.db` directly via `sqlite3`, `better-sqlite3`, or `node -e require('better-sqlite3')`; the engine owns a single-writer WAL connection. Use `gsd_milestone_status`, `gsd_journal_query`, or other `gsd_*` tools.\n\n### Ask vs infer\n\nAsk only when the answer materially affects the result and cannot be derived from repo evidence, docs, runtime behavior, or command output. If multiple interpretations are reasonable, choose the smallest safe reversible action.\n\n### Code structure and abstraction\n\n- Prefer small primitives over monoliths; extract around real seams.\n- Separate orchestration from implementation.\n- Prefer boring standard abstractions over clever custom frameworks.\n- Do not abstract speculatively; keep code local until the seam stabilizes.\n- Preserve local consistency.\n\n### Verification and definition of done\n\nVerify according to task type: bug fix → rerun repro, script fix → rerun command, UI fix → verify in browser, refactor → run tests, env fix → rerun blocked workflow, file ops → confirm filesystem state, docs → verify paths and commands match reality.\n\nFor non-trivial work, verify both the feature and the failure/diagnostic surface. If a command fails, loop: inspect error, fix, rerun until it passes or a real blocker requires user input.\n\nWork is not done when the code compiles. Work is done when the verification passes.\n\n### Agent-First Observability\n\nFor relevant work: add health/status surfaces, persist failure state (last error, phase, timestamp, retry count), verify both happy path and at least one diagnostic signal. Never log secrets. Remove noisy one-off instrumentation before finishing unless it provides durable diagnostic value.\n\n### Root-cause-first debugging\n\nFix root causes, not symptoms. If applying temporary mitigation, label it and preserve the path to the real fix. Never add guards/try-catch to suppress undiagnosed errors.\n\n## Communication\n\n- All plans are for the agent's own execution, not an imaginary team's. No enterprise patterns unless explicitly asked for.\n- Push back on security issues, performance problems, anti-patterns, and unnecessary complexity with concrete reasoning - especially during discussion and planning.\n- Between tool calls, narrate decisions, discoveries, phase transitions, and verification outcomes in one or two complete sentences. Do not narrate every call or the obvious.\n- State uncertainty plainly: \"Not sure this handles X - testing it.\" No performed confidence, no hedging paragraphs.\n- All user-visible narration must be grammatical English. Do not emit compressed planner notes like \"Need inspect X\". If it fits a commit comment or standup note, it is acceptable.\n- When debugging, stay curious. Problems are puzzles. Say what's interesting about the failure before reaching for fixes.\n- After completing a task, give a brief summary and 2-4 numbered next-step options; last option is always \"Other\". Omit the list for strict output formats.\n\nGood narration: \"Three existing handlers follow a middleware pattern - using that instead of a custom wrapper.\"\nGood narration: \"Tests pass. Running slice-level verification.\"\nGood narration: \"I need the task-plan template first, then I'll compare the existing T01 and T02 plans.\"\nBad narration: \"Reading the file now.\" / \"Let me check this.\" / \"I'll look at the tests next.\"\nBad narration: \"Need create plan artifact likely requires template maybe read existing task plans.\"\n","src/resources/extensions/gsd/skills/gsd-headless/SKILL.md":"---\nname: gsd-headless\ndescription: Orchestrate GSD (Get Shit Done) projects programmatically via headless CLI. Use when an agent needs to create milestones from specs, execute software development workflows, monitor task progress, check project status, or control GSD execution (pause/stop/skip/steer). Triggers on requests to \"run gsd\", \"create milestone\", \"execute project\", \"check gsd status\", \"orchestrate development\", \"run headless workflow\", or any programmatic interaction with the GSD project management system. Essential for building orchestrators that coordinate multiple GSD workers.\n---\n\n# GSD Headless Orchestration\n\nRun GSD commands without TUI via `gsd headless`. Spawns an RPC child process, auto-responds to UI prompts, streams progress.\n\n## Command Syntax\n\n```bash\ngsd headless [flags] [command] [args...]\n```\n\n**Flags:**\n- `--timeout N` — overall timeout in ms (default 300000)\n- `--json` — JSONL event stream to stdout\n- `--model ID` — override LLM model\n- `--verbose` — show tool calls in progress output\n- `--supervised` — forward interactive UI requests to orchestrator via stdout/stdin\n- `--response-timeout N` — timeout for orchestrator response in supervised mode (default 30000)\n- `--max-restarts N` — auto-restart on crash with backoff (default 3, 0 to disable)\n- `--answers <path>` — pre-supply answers and secrets from JSON file\n- `--events <types>` — filter JSONL output to specific event types (comma-separated, implies `--json`)\n\n**Exit codes:** 0=complete, 1=error/timeout, 2=blocked\n\n## Core Workflows\n\n### 1. Create + Execute a Milestone (end-to-end)\n\n```bash\ngsd headless new-milestone --context spec.md --auto\n```\n\nReads spec, bootstraps `.gsd/`, creates milestone, then chains into auto-mode executing all phases (discuss → research → plan → execute → summarize → complete).\n\nExtra flags for `new-milestone`: `--context <path>` (use `-` for stdin), `--context-text <text>`, `--auto`.\n\n### 2. Run All Queued Work\n\n```bash\ngsd headless auto\n```\n\nDefault command. Loops through all pending units until milestone complete or blocked.\n\n### 3. Run One Unit\n\n```bash\ngsd headless next\n```\n\nExecute exactly one unit (task/slice/milestone step), then exit. Ideal for step-by-step orchestration with external decision logic between steps.\n\n### 4. Instant State Snapshot (no LLM)\n\n```bash\ngsd headless query\n```\n\nReturns a single JSON object with the full project snapshot — no LLM session, instant (~50ms). **This is the recommended way for orchestrators to inspect state.**\n\n```json\n{\n  \"state\": { \"phase\": \"executing\", \"activeMilestone\": {...}, \"activeSlice\": {...}, \"progress\": {...}, \"registry\": [...] },\n  \"next\":  { \"action\": \"dispatch\", \"unitType\": \"execute-task\", \"unitId\": \"M001/S01/T01\" },\n  \"cost\":  { \"workers\": [{ \"milestoneId\": \"M001\", \"cost\": 1.50, ... }], \"total\": 1.50 }\n}\n```\n\n```bash\n# What phase is the project in?\ngsd headless query | jq '.state.phase'\n\n# What would auto-mode do next?\ngsd headless query | jq '.next'\n\n# Total spend across parallel workers\ngsd headless query | jq '.cost.total'\n```\n\n### 5. Dispatch Specific Phase\n\n```bash\ngsd headless dispatch research|plan|execute|complete|reassess|uat|replan\n```\n\nForce-route to a specific phase, bypassing normal state-machine routing.\n\n## Orchestrator Patterns\n\n### Poll-and-React Loop\n\n```bash\n# Instant state check — no LLM cost\nPHASE=$(gsd headless query | jq -r '.state.phase')\nNEXT_ACTION=$(gsd headless query | jq -r '.next.action')\n\ncase \"$PHASE\" in\n  complete) echo \"Done\" ;;\n  blocked)  echo \"Needs intervention\" ;;\n  *)        [ \"$NEXT_ACTION\" = \"dispatch\" ] && gsd headless next ;;\nesac\n```\n\n### Step-by-Step with Monitoring\n\n```bash\nwhile true; do\n  gsd headless next\n  EXIT=$?\n  [ $EXIT -ne 0 ] && break\n  # Instant progress check between steps\n  gsd headless query | jq '{phase: .state.phase, progress: .state.progress}'\ndone\n```\n\n### Multi-Session Orchestration\n\nGSD tracks concurrent workers via file-based IPC in `.gsd/parallel/`. See [references/multi-session.md](references/multi-session.md) for the full architecture.\n\n**Quick overview:**\n\nEach worker spawns with `GSD_MILESTONE_LOCK=M00X` + its own git worktree. Workers write heartbeats to `.gsd/parallel/<milestoneId>.status.json`. The orchestrator enumerates all status files to get a dashboard of all workers, and sends commands via signal files.\n\n```bash\n# Spawn a worker for milestone M001 in its worktree\nGSD_MILESTONE_LOCK=M001 GSD_PARALLEL_WORKER=1 \\\n  gsd headless --json auto \\\n  --cwd .gsd/worktrees/M001 2>worker-M001.log &\n\n# Monitor all workers: read .gsd/parallel/*.status.json\nfor f in .gsd/parallel/*.status.json; do\n  jq '{mid: .milestoneId, state: .state, unit: .currentUnit.id, cost: .cost}' \"$f\"\ndone\n\n# Send pause signal to M001\necho '{\"signal\":\"pause\",\"sentAt\":'$(date +%s000)',\"from\":\"coordinator\"}' \\\n  > .gsd/parallel/M001.signal.json\n```\n\n**Status file fields:** `milestoneId`, `pid`, `state` (running/paused/stopped/error), `currentUnit`, `completedUnits`, `cost`, `lastHeartbeat`, `startedAt`, `worktreePath`.\n\n**Signal commands:** `pause`, `resume`, `stop`, `rebase`.\n\n**Liveness detection:** PID alive check (`kill -0 $pid`) + heartbeat freshness (30s timeout). Stale sessions are auto-cleaned.\n\n**For multiple projects:** each project has its own `.gsd/` directory. The orchestrator must track `(projectPath, milestoneId)` tuples externally.\n\n### JSONL Event Stream\n\nUse `--json` to get real-time events on stdout for downstream processing:\n\n```bash\ngsd headless --json auto 2>/dev/null | while read -r line; do\n  TYPE=$(echo \"$line\" | jq -r '.type')\n  case \"$TYPE\" in\n    tool_execution_start) echo \"Tool: $(echo \"$line\" | jq -r '.toolName')\" ;;\n    extension_ui_request) echo \"GSD: $(echo \"$line\" | jq -r '.message // .title // empty')\" ;;\n    agent_end) echo \"Session ended\" ;;\n  esac\ndone\n```\n\nEvent types: `agent_start`, `agent_end`, `tool_execution_start`, `tool_execution_end`, `extension_ui_request`, `message_update`, `error`.\n\n### Filtered Event Stream\n\nUse `--events` to receive only specific event types — reduces noise for orchestrators:\n\n```bash\n# Only phase-relevant events\ngsd headless --events agent_end,extension_ui_request auto 2>/dev/null\n\n# Only tool execution events\ngsd headless --events tool_execution_start,tool_execution_end auto\n```\n\nThe filter applies only to stdout output. Internal processing (completion detection, supervised mode, answer injection) is unaffected — all events are still processed internally.\n\nAvailable event types: `agent_start`, `agent_end`, `tool_execution_start`, `tool_execution_end`, `tool_execution_update`, `extension_ui_request`, `message_start`, `message_end`, `message_update`, `turn_start`, `turn_end`.\n\n## Answer Injection\n\nPre-supply answers and secrets for headless runs via `--answers`:\n\n```bash\ngsd headless --answers answers.json auto\n```\n\nAnswer file schema:\n```json\n{\n  \"questions\": { \"question_id\": \"selected_option\" },\n  \"secrets\": { \"API_KEY\": \"sk-...\" },\n  \"defaults\": { \"strategy\": \"first_option\" }\n}\n```\n\n- **questions** — question ID → answer (string or string[])\n- **secrets** — env var → value, injected into child process env\n- **defaults.strategy** — `\"first_option\"` (default) or `\"cancel\"` for unmatched\n\nSee [references/answer-injection.md](references/answer-injection.md) for full details.\n\n## GSD Project Structure\n\nAll state lives in `.gsd/` as markdown files (version-controllable):\n\n```\n.gsd/\n  milestones/M001/\n    M001-CONTEXT.md      # Requirements, scope, decisions\n    M001-ROADMAP.md      # Slices with tasks, dependencies, checkboxes\n    M001-SUMMARY.md      # Completion summary\n    slices/S01/\n      S01-PLAN.md        # Task list\n      S01-SUMMARY.md     # Slice summary with frontmatter\n      tasks/T01-PLAN.md  # Individual task spec\n```\n\nState is derived from files on disk — checkboxes in ROADMAP.md are the source of truth for completion.\n\n## All Headless Commands\n\nQuick reference — see [references/commands.md](references/commands.md) for the complete list.\n\n| Command | Purpose |\n|---------|---------|\n| `auto` | Run all queued units (default) |\n| `next` | Run one unit |\n| `query` | Instant JSON snapshot — state, next dispatch, costs (no LLM) |\n| `new-milestone` | Create milestone from spec |\n| `queue` | Queue/reorder milestones |\n| `history` | View execution history |\n| `stop` / `pause` | Control auto-mode |\n| `dispatch <phase>` | Force specific phase |\n| `skip` / `undo` | Unit control |\n| `doctor` | Health check + auto-fix |\n| `steer <desc>` | Hard-steer plan mid-execution |\n","src/resources/extensions/gsd/skills/gsd-headless/references/answer-injection.md":"# Answer Injection\n\nPre-supply answers to eliminate interactive prompts during headless execution.\n\n## CLI Usage\n\n```bash\ngsd headless --answers answers.json auto\ngsd headless --answers answers.json new-milestone --context spec.md --auto\n```\n\nThe `--answers` flag takes a path to a JSON file containing pre-supplied answers and secrets.\n\n## Answer File Schema\n\n```json\n{\n  \"questions\": {\n    \"question_id\": \"selected_option_label\",\n    \"multi_select_question\": [\"option_a\", \"option_b\"]\n  },\n  \"secrets\": {\n    \"API_KEY\": \"sk-...\",\n    \"DATABASE_URL\": \"postgres://...\"\n  },\n  \"defaults\": {\n    \"strategy\": \"first_option\"\n  }\n}\n```\n\n### Fields\n\n- **questions**: Map question ID → answer. String for single-select, string[] for multi-select.\n- **secrets**: Map env var name → value. Injected as environment variables into the RPC child process. The child's `checkExistingEnvKeys()` detects them in `process.env` and marks them as \"already set\" — no interactive prompt needed.\n- **defaults.strategy**: Fallback for unmatched questions.\n  - `\"first_option\"` — auto-select first available option (default)\n  - `\"cancel\"` — cancel the request\n\n## Secrets Mechanism\n\nSecrets are injected via the `RpcClient` `env` option, which merges them into the child process's `process.env`. This means:\n\n1. The headless orchestrator reads the answer file\n2. Secret values are passed as `env` to `RpcClient`\n3. The child process spawns with these env vars set\n4. When `secure_env_collect` runs, `checkExistingEnvKeys()` finds the keys already in `process.env`\n5. The tool skips the interactive prompt and reports the keys as \"already configured\"\n\nSecrets are never logged or included in event streams.\n\n## How It Works\n\nTwo-phase correlation:\n1. **Observe** `tool_execution_start` events for `ask_user_questions` — extracts question metadata (ID, options, allowMultiple)\n2. **Match** subsequent `extension_ui_request` events to metadata, respond with pre-supplied answer\n\nHandles out-of-order events (extension_ui_request can arrive before tool_execution_start in RPC mode) via deferred processing queue with 500ms timeout.\n\n## Coexistence with --supervised\n\nBoth `--answers` and `--supervised` can be active simultaneously. Priority order:\n1. Answer injector tries first\n2. If no answer found, supervised mode takes over\n3. If no orchestrator response, auto-responder kicks in after timeout\n\n## Without Answer Injection\n\nHeadless mode has built-in auto-responders:\n- **select** → picks first option\n- **confirm** → auto-confirms\n- **input** → empty string\n- **editor** → returns prefill or empty\n\nAnswer injection overrides these defaults with specific answers when precision matters.\n\n## Diagnostics\n\nThe injector tracks stats printed in the summary:\n- `questionsAnswered` / `questionsDefaulted`\n- `secretsProvided`\n\nUnused question IDs and secret keys are warned about at the end.\n","src/resources/extensions/gsd/skills/gsd-headless/references/commands.md":"# GSD Commands Reference\n\nAll commands can be run via `gsd headless [command]`.\n\n## Workflow Commands\n\n| Command | Description |\n|---------|-------------|\n| `auto` | Autonomous mode — loop until milestone complete (default) |\n| `next` | Step mode — execute one unit, then exit |\n| `stop` | Stop auto-mode gracefully |\n| `pause` | Pause auto-mode (preserves state, resumable) |\n| `new-milestone` | Create milestone from specification (requires `--context`) |\n| `dispatch <phase>` | Force-dispatch: research, plan, execute, complete, reassess, uat, replan |\n| `discuss` | Start guided milestone/slice discussion |\n\n## State Inspection\n\n| Command | Description |\n|---------|-------------|\n| `query` | **Instant JSON snapshot** — state, next dispatch, parallel costs. No LLM, ~50ms. Recommended for orchestrators. |\n| `status` | Progress dashboard (TUI overlay — useful interactively, not for parsing) |\n| `visualize` | Workflow visualizer (deps, metrics, timeline) |\n| `history` | Execution history (supports --cost, --phase, --model, limit) |\n\n## Unit Control\n\n| Command | Description |\n|---------|-------------|\n| `skip` | Prevent a unit from auto-mode dispatch |\n| `undo` | Revert last completed unit (--force flag) |\n| `steer <desc>` | Hard-steer plan documents during execution |\n| `queue` | Queue and reorder future milestones |\n| `capture` | Fire-and-forget thought capture |\n| `triage` | Manually trigger triage of pending captures |\n\n## Configuration & Health\n\n| Command | Description |\n|---------|-------------|\n| `prefs` | Manage preferences (global/project/status/wizard/setup) |\n| `config` | Set API keys for external tools |\n| `doctor` | Runtime health checks with auto-fix |\n| `hooks` | Show configured post-unit and pre-dispatch hooks |\n| `knowledge <rule\\|pattern\\|lesson>` | Add persistent project knowledge |\n| `cleanup` | Remove merged branches or snapshots |\n| `export` | Export results (--json, --markdown) |\n| `migrate` | Migrate v1 .planning directory to DB-backed .gsd with backup and audit |\n| `remote` | Control remote auto-mode (slack, discord, status, disconnect) |\n| `inspect` | Show SQLite DB diagnostics (schema, row counts) |\n| `forensics` | Post-mortem investigation of auto-mode failures |\n\n## Phases\n\nGSD workflows progress through these phases:\n`pre-planning` → `needs-discussion` → `discussing` → `researching` → `planning` → `executing` → `verifying` → `summarizing` → `advancing` → `validating-milestone` → `completing-milestone` → `complete`\n\nSpecial phases: `paused`, `blocked`, `replanning-slice`\n\n## Hierarchy\n\n- **Milestone**: Shippable version (4-10 slices, 1-4 weeks)\n- **Slice**: One demoable vertical capability (1-7 tasks, 1-3 days)\n- **Task**: One context-window-sized unit of work (one session)\n","src/resources/extensions/gsd/skills/gsd-headless/references/multi-session.md":"# Multi-Session Orchestration\n\nHow to run and monitor multiple concurrent GSD sessions.\n\n## Architecture\n\nGSD uses **file-based IPC** — no sockets or ports. All coordination happens through JSON files in `.gsd/parallel/`.\n\n```\n.gsd/parallel/\n├── M001.status.json    # Worker heartbeat + state\n├── M001.signal.json    # Coordinator → worker commands (ephemeral)\n├── M002.status.json\n├── M003.status.json\n└── ...\n```\n\n## Worker Isolation\n\nEach worker gets:\n1. **`GSD_MILESTONE_LOCK=M00X`** — state derivation only sees this milestone\n2. **`GSD_PARALLEL_WORKER=1`** — prevents nested parallel spawns\n3. **Own git worktree** at `.gsd/worktrees/M00X/` — branch `milestone/M00X`\n\nWorkers cannot interfere with each other. Each has its own filesystem and git branch.\n\n## Status File Schema\n\nWritten atomically (`.tmp` + rename) by each worker at `.gsd/parallel/<milestoneId>.status.json`:\n\n```json\n{\n  \"milestoneId\": \"M001\",\n  \"pid\": 12345,\n  \"state\": \"running\",\n  \"currentUnit\": {\n    \"type\": \"task\",\n    \"id\": \"T03\",\n    \"startedAt\": 1710000000000\n  },\n  \"completedUnits\": 7,\n  \"cost\": 1.23,\n  \"lastHeartbeat\": 1710000015000,\n  \"startedAt\": 1710000000000,\n  \"worktreePath\": \".gsd/worktrees/M001\"\n}\n```\n\n**States:** `running`, `paused`, `stopped`, `error`\n\n## Signal Files\n\nCoordinator writes to `.gsd/parallel/<milestoneId>.signal.json`. Worker consumes and deletes on next dispatch cycle.\n\n```json\n{\n  \"signal\": \"pause\",\n  \"sentAt\": 1710000020000,\n  \"from\": \"coordinator\"\n}\n```\n\n**Signals:** `pause`, `resume`, `stop`, `rebase`\n\n## Spawning Workers\n\n```bash\n# Spawn worker in its worktree\nGSD_MILESTONE_LOCK=M001 \\\nGSD_PARALLEL_WORKER=1 \\\n  gsd headless --json auto 2>logs/M001.log &\nWORKER_PID=$!\n```\n\nWorkers emit JSONL events on stdout when `--json` is set.\n\n## Monitoring All Workers\n\n```bash\n# Dashboard: enumerate all status files\nfor f in .gsd/parallel/*.status.json; do\n  [ -f \"$f\" ] || continue\n  jq -r '[.milestoneId, .state, (.currentUnit.id // \"idle\"), \"\\(.cost | tostring)$\"] | join(\"\\t\")' \"$f\"\ndone\n\n# Liveness check\nfor f in .gsd/parallel/*.status.json; do\n  PID=$(jq -r '.pid' \"$f\")\n  MID=$(jq -r '.milestoneId' \"$f\")\n  if kill -0 \"$PID\" 2>/dev/null; then\n    echo \"$MID: alive (pid=$PID)\"\n  else\n    echo \"$MID: DEAD (pid=$PID) — cleanup needed\"\n    rm \"$f\"\n  fi\ndone\n```\n\n## Sending Commands\n\n```bash\n# Pause a worker\nsend_signal() {\n  local MID=$1 SIGNAL=$2\n  echo \"{\\\"signal\\\":\\\"$SIGNAL\\\",\\\"sentAt\\\":$(date +%s000),\\\"from\\\":\\\"coordinator\\\"}\" \\\n    > \".gsd/parallel/${MID}.signal.json\"\n}\n\nsend_signal M001 pause\nsend_signal M002 stop\nsend_signal M003 resume\n```\n\n## Budget Enforcement\n\nUse `gsd headless query` for instant aggregate cost:\n```bash\nTOTAL=$(gsd headless query | jq -r '.cost.total')\nCEILING=50.00\nif (( $(echo \"$TOTAL > $CEILING\" | bc -l) )); then\n  echo \"Budget exceeded ($TOTAL > $CEILING) — stopping all\"\n  for f in .gsd/parallel/*.status.json; do\n    MID=$(jq -r '.milestoneId' \"$f\")\n    send_signal \"$MID\" stop\n  done\nfi\n```\n\n## Stale Session Cleanup\n\nA session is stale when:\n- PID is dead (`kill -0 $pid` fails), OR\n- `lastHeartbeat` is older than 30 seconds\n\n```bash\nNOW=$(date +%s000)\nSTALE_THRESHOLD=30000\nfor f in .gsd/parallel/*.status.json; do\n  PID=$(jq -r '.pid' \"$f\")\n  HB=$(jq -r '.lastHeartbeat' \"$f\")\n  AGE=$((NOW - HB))\n  if ! kill -0 \"$PID\" 2>/dev/null || [ \"$AGE\" -gt \"$STALE_THRESHOLD\" ]; then\n    echo \"Stale: $(jq -r '.milestoneId' \"$f\") — removing\"\n    rm \"$f\"\n  fi\ndone\n```\n\n## Multi-Project Orchestration\n\nWithin one project, milestones are tracked automatically in `.gsd/parallel/`. For orchestrating across **multiple projects**, maintain an external registry:\n\n```json\n{\n  \"sessions\": [\n    { \"project\": \"/path/to/project-a\", \"milestoneId\": \"M001\" },\n    { \"project\": \"/path/to/project-b\", \"milestoneId\": \"M001\" },\n    { \"project\": \"/path/to/project-b\", \"milestoneId\": \"M002\" }\n  ]\n}\n```\n\nThen poll each project's `.gsd/parallel/` directory. GSD has no cross-project awareness — the orchestrator must bridge this gap.\n\n## Built-in Parallel Commands\n\nInside an interactive GSD session, these commands manage the parallel orchestrator:\n\n| Command | Description |\n|---------|-------------|\n| `/gsd parallel start` | Analyze eligibility, spawn workers |\n| `/gsd parallel status` | Show all workers, costs, progress |\n| `/gsd parallel stop [MID]` | Stop one or all workers |\n| `/gsd parallel pause [MID]` | Pause without killing |\n| `/gsd parallel resume [MID]` | Resume paused worker |\n| `/gsd parallel merge [MID]` | Merge completed milestone branch |\n","src/resources/extensions/gsd/templates/milestone-summary.md":"---\nid: {{milestoneId}}\nprovides:\n  - {{whatThisMilestoneProvides}}\nkey_decisions:\n  - {{decision}}\npatterns_established:\n  - {{pattern}}\nobservability_surfaces:\n  - {{status endpoint, structured log, persisted failure state, diagnostic command, or none}}\nrequirement_outcomes:\n  - id: {{requirementId}}\n    from_status: {{active|blocked|deferred}}\n    to_status: {{validated|deferred|blocked|out_of_scope}}\n    proof: {{whatEvidenceSupportsThisTransition}}\nduration: {{duration}}\nverification_result: passed\ncompleted_at: {{date}}\n---\n\n# {{milestoneId}}: {{milestoneTitle}}\n\n<!-- One-liner must say what the milestone actually delivered, not just that it completed.\n     Good: \"State machine integrity with completing-milestone gating, doctor audits, and observability validation\"\n     Bad: \"Milestone 2 completed\" -->\n\n**{{oneLiner}}**\n\n## What Happened\n\n<!-- Cross-slice narrative: compress all slice summaries into a coherent story.\n     Focus on what was built, how the slices connected, and what the milestone\n     achieved as a whole — not a task-by-task replay. -->\n\n{{crossSliceNarrative}}\n\n## Cross-Slice Verification\n\n<!-- How were the milestone's success criteria verified?\n     Reference specific tests, commands, browser checks, or observable behaviors.\n     Each success criterion from the roadmap should have a corresponding verification entry. -->\n\n{{howSuccessCriteriaWereVerified}}\n\n## Requirement Changes\n\n<!-- Transitions with evidence. Each requirement that changed status during this milestone\n     should be listed with the proof that supports the transition. -->\n\n- {{requirementId}}: {{fromStatus}} → {{toStatus}} — {{evidence}}\n\n## Decision Re-evaluation\n\n<!-- Review decisions from this milestone. OMIT if no decisions need re-evaluation. -->\n\n| Decision | Original Rationale | Still Valid? | Action |\n|----------|-------------------|-------------|--------|\n| {{decisionId}} | {{originalRationale}} | {{yes/no/partially}} | {{keep/revise/supersede}} |\n\n## Forward Intelligence\n\n<!-- Write what you wish you'd known at the start of this milestone.\n     This section is read by the next milestone's planning and research steps.\n     Be specific and concrete — this is the most valuable context you can transfer. -->\n\n### What the next milestone should know\n- {{insightThatWouldHelpDownstreamWork}}\n\n### What's fragile\n- {{fragileAreaOrThinImplementation}} — {{whyItMatters}}\n\n### Authoritative diagnostics\n- {{whereAFutureAgentShouldLookFirst}} — {{whyThisSignalIsTrustworthy}}\n\n### What assumptions changed\n- {{originalAssumption}} — {{whatActuallyHappened}}\n\n## Files Created/Modified\n\n- `{{filePath}}` — {{description}}\n- `{{filePath}}` — {{description}}\n","src/resources/extensions/gsd/templates/slice-summary.md":"---\nid: {{sliceId}}\nparent: {{milestoneId}}\nmilestone: {{milestoneId}}\nprovides:\n  - {{whatThisSliceProvides}}\nrequires:\n  - slice: {{depSliceId}}\n    provides: {{whatWasConsumed}}\naffects:\n  - {{downstreamSliceId}}\nkey_files:\n  - {{filePath}}\nkey_decisions:\n  - {{decision}}\npatterns_established:\n  - {{pattern}}\nobservability_surfaces:\n  - {{status endpoint, structured log, persisted failure state, diagnostic command, or none}}\ndrill_down_paths:\n  - {{pathToTaskSummary}}\nduration: {{duration}}\nverification_result: passed\ncompleted_at: {{date}}\n---\n\n# {{sliceId}}: {{sliceTitle}}\n\n<!-- One-liner must say what actually shipped, not just that work completed.\n     Good: \"Structured job status endpoint with persisted failure diagnostics\"\n     Bad: \"Status feature implemented\" -->\n\n**{{oneLiner}}**\n\n## What Happened\n\n{{narrative — compress task summaries into a coherent story}}\n\n## Verification\n\n{{whatWasVerifiedAcrossAllTasks — tests, builds, manual checks}}\n\n<!-- If the project has no REQUIREMENTS.md, omit all four requirement sections below entirely — do not fill them with \"none\". These sections only apply when requirements are being actively tracked. -->\n## Requirements Advanced\n\n- {{requirementId}} — {{howThisSliceAdvancedIt}}\n\n## Requirements Validated\n\n- {{requirementId}} — {{whatProofNowMakesItValidated}}\n\n## New Requirements Surfaced\n\n- {{newRequirementOr_none}}\n\n## Requirements Invalidated or Re-scoped\n\n- {{requirementIdOr_none}} — {{what changed}}\n\n## Operational Readiness\n\n<!-- Q8: How will ops know it's healthy/broken? OMIT ENTIRELY for simple slices with no runtime concerns. -->\n\n- **Health signal**: {{howToConfirmHealthy — health endpoint, heartbeat log, metric, or N/A}}\n- **Failure signal**: {{howToDetectBroken — error rate spike, alert, log pattern, or N/A}}\n- **Recovery**: {{selfRecoverOrRestart — auto-reconnect, circuit breaker, manual restart, or N/A}}\n- **Monitoring gaps**: {{silentFailureModes — background jobs, cache eviction, memory pressure, or none}}\n\n## Deviations\n\n<!-- Deviations are unplanned changes to the written plan, not ordinary debugging inside the plan's intended scope. -->\n\n{{deviationsFromPlan_OR_none}}\n\n## Known Limitations\n\n<!-- Known limitations are real gaps, rough edges, or deferred constraints that still exist after this slice shipped. -->\n\n{{whatDoesntWorkYet_OR_whatWasDeferredToLaterSlices}}\n\n## Follow-ups\n\n<!-- Follow-ups are concrete next actions discovered during execution, not a restatement of known limitations. -->\n\n{{workDeferredOrDiscoveredDuringExecution_OR_none}}\n\n## Files Created/Modified\n\n- `{{filePath}}` — {{description}}\n- `{{filePath}}` — {{description}}\n\n## Forward Intelligence\n\n<!-- Write what you wish you'd known at the start of this slice.\n     This section is read by the next slice's planning and research steps.\n     Be specific and concrete — this is the most valuable context you can transfer. -->\n\n### What the next slice should know\n- {{insightThatWouldHelpDownstreamWork}}\n\n### What's fragile\n- {{fragileAreaOrThinImplementation}} — {{whyItMatters}}\n\n### Authoritative diagnostics\n- {{whereAFutureAgentShouldLookFirst}} — {{whyThisSignalIsTrustworthy}}\n\n### What assumptions changed\n- {{originalAssumption}} — {{whatActuallyHappened}}\n","src/resources/extensions/gsd/templates/task-summary.md":"---\nid: {{taskId}}\nparent: {{sliceId}}\nmilestone: {{milestoneId}}\nprovides:\n  - {{whatThisTaskProvides}}\nkey_files:\n  - {{filePath}}\nkey_decisions:\n  - {{decision}}\npatterns_established:\n  - {{pattern}}\nobservability_surfaces:\n  - {{status endpoint, structured log, persisted failure state, diagnostic command, or none}}\nduration: {{duration}}\nverification_result: passed\ncompleted_at: {{date}}\n# Set blocker_discovered: true only if execution revealed the remaining slice plan\n# is fundamentally invalid (wrong API, missing capability, architectural mismatch).\n# Do NOT set true for ordinary bugs, minor deviations, or fixable issues.\nblocker_discovered: false\n---\n\n# {{taskId}}: {{taskTitle}}\n\n<!-- One-liner must say what actually shipped, not just that work completed.\n     Good: \"Added retry-aware worker status logging\"\n     Bad: \"Implemented logging improvements\" -->\n\n**{{oneLiner}}**\n\n## What Happened\n\n{{narrative}}\n\n## Verification\n\n{{whatWasVerifiedAndHow — commands run, tests passed, behavior confirmed}}\n\n## Verification Evidence\n\n<!-- Populated from verification gate output. If the gate ran, fill in the table below.\n     If no gate ran (e.g., no verification commands discovered), note that. -->\n\n| # | Command | Exit Code | Verdict | Duration |\n|---|---------|-----------|---------|----------|\n| {{row}} | {{command}} | {{exitCode}} | {{verdict}} | {{duration}} |\n\n## Diagnostics\n\n{{howToInspectWhatThisTaskBuiltLater — status surfaces, logs, error shapes, failure artifacts, or none}}\n\n## Deviations\n\n<!-- Deviations are unplanned changes to the written task plan, not ordinary debugging during implementation. -->\n\n{{deviationsFromPlan_OR_none}}\n\n## Known Issues\n\n{{issuesDiscoveredButNotFixed_OR_none}}\n\n## Files Created/Modified\n\n- `{{filePath}}` — {{description}}\n- `{{filePath}}` — {{description}}\n","src/resources/skills/accessibility/SKILL.md":"---\nname: accessibility\ndescription: Audit and improve web accessibility following WCAG 2.1 guidelines. Use when asked to \"improve accessibility\", \"a11y audit\", \"WCAG compliance\", \"screen reader support\", \"keyboard navigation\", or \"make accessible\".\nlicense: MIT\nmetadata:\n  author: web-quality-skills\n  version: \"1.0\"\n---\n\n# Accessibility (a11y)\n\nComprehensive accessibility guidelines based on WCAG 2.1 and Lighthouse accessibility audits. Goal: make content usable by everyone, including people with disabilities.\n\n## WCAG Principles: POUR\n\n| Principle | Description |\n|-----------|-------------|\n| **P**erceivable | Content can be perceived through different senses |\n| **O**perable | Interface can be operated by all users |\n| **U**nderstandable | Content and interface are understandable |\n| **R**obust | Content works with assistive technologies |\n\n## Conformance levels\n\n| Level | Requirement | Target |\n|-------|-------------|--------|\n| **A** | Minimum accessibility | Must pass |\n| **AA** | Standard compliance | Should pass (legal requirement in many jurisdictions) |\n| **AAA** | Enhanced accessibility | Nice to have |\n\n---\n\n## Perceivable\n\n### Text alternatives (1.1)\n\n**Images require alt text:**\n```html\n<!-- ❌ Missing alt -->\n<img src=\"chart.png\">\n\n<!-- ✅ Descriptive alt -->\n<img src=\"chart.png\" alt=\"Bar chart showing 40% increase in Q3 sales\">\n\n<!-- ✅ Decorative image (empty alt) -->\n<img src=\"decorative-border.png\" alt=\"\" role=\"presentation\">\n\n<!-- ✅ Complex image with longer description -->\n<figure>\n  <img src=\"infographic.png\" alt=\"2024 market trends infographic\" \n       aria-describedby=\"infographic-desc\">\n  <figcaption id=\"infographic-desc\">\n    <!-- Detailed description -->\n  </figcaption>\n</figure>\n```\n\n**Icon buttons need accessible names:**\n```html\n<!-- ❌ No accessible name -->\n<button><svg><!-- menu icon --></svg></button>\n\n<!-- ✅ Using aria-label -->\n<button aria-label=\"Open menu\">\n  <svg aria-hidden=\"true\"><!-- menu icon --></svg>\n</button>\n\n<!-- ✅ Using visually hidden text -->\n<button>\n  <svg aria-hidden=\"true\"><!-- menu icon --></svg>\n  <span class=\"visually-hidden\">Open menu</span>\n</button>\n```\n\n**Visually hidden class:**\n```css\n.visually-hidden {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: -1px;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  white-space: nowrap;\n  border: 0;\n}\n```\n\n### Color contrast (1.4.3, 1.4.6)\n\n| Text Size | AA minimum | AAA enhanced |\n|-----------|------------|--------------|\n| Normal text (< 18px / < 14px bold) | 4.5:1 | 7:1 |\n| Large text (≥ 18px / ≥ 14px bold) | 3:1 | 4.5:1 |\n| UI components & graphics | 3:1 | 3:1 |\n\n```css\n/* ❌ Low contrast (2.5:1) */\n.low-contrast {\n  color: #999;\n  background: #fff;\n}\n\n/* ✅ Sufficient contrast (7:1) */\n.high-contrast {\n  color: #333;\n  background: #fff;\n}\n\n/* ✅ Focus states need contrast too */\n:focus-visible {\n  outline: 2px solid #005fcc;\n  outline-offset: 2px;\n}\n```\n\n**Don't rely on color alone:**\n```html\n<!-- ❌ Only color indicates error -->\n<input class=\"error-border\">\n<style>.error-border { border-color: red; }</style>\n\n<!-- ✅ Color + icon + text -->\n<div class=\"field-error\">\n  <input aria-invalid=\"true\" aria-describedby=\"email-error\">\n  <span id=\"email-error\" class=\"error-message\">\n    <svg aria-hidden=\"true\"><!-- error icon --></svg>\n    Please enter a valid email address\n  </span>\n</div>\n```\n\n### Media alternatives (1.2)\n\n```html\n<!-- Video with captions -->\n<video controls>\n  <source src=\"video.mp4\" type=\"video/mp4\">\n  <track kind=\"captions\" src=\"captions.vtt\" srclang=\"en\" label=\"English\" default>\n  <track kind=\"descriptions\" src=\"descriptions.vtt\" srclang=\"en\" label=\"Descriptions\">\n</video>\n\n<!-- Audio with transcript -->\n<audio controls>\n  <source src=\"podcast.mp3\" type=\"audio/mp3\">\n</audio>\n<details>\n  <summary>Transcript</summary>\n  <p>Full transcript text...</p>\n</details>\n```\n\n---\n\n## Operable\n\n### Keyboard accessible (2.1)\n\n**All functionality must be keyboard accessible:**\n```javascript\n// ❌ Only handles click\nelement.addEventListener('click', handleAction);\n\n// ✅ Handles both click and keyboard\nelement.addEventListener('click', handleAction);\nelement.addEventListener('keydown', (e) => {\n  if (e.key === 'Enter' || e.key === ' ') {\n    e.preventDefault();\n    handleAction();\n  }\n});\n```\n\n**No keyboard traps:**\n```javascript\n// Modal focus management\nfunction openModal(modal) {\n  const focusableElements = modal.querySelectorAll(\n    'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n  );\n  const firstElement = focusableElements[0];\n  const lastElement = focusableElements[focusableElements.length - 1];\n  \n  // Trap focus within modal\n  modal.addEventListener('keydown', (e) => {\n    if (e.key === 'Tab') {\n      if (e.shiftKey && document.activeElement === firstElement) {\n        e.preventDefault();\n        lastElement.focus();\n      } else if (!e.shiftKey && document.activeElement === lastElement) {\n        e.preventDefault();\n        firstElement.focus();\n      }\n    }\n    if (e.key === 'Escape') {\n      closeModal();\n    }\n  });\n  \n  firstElement.focus();\n}\n```\n\n### Focus visible (2.4.7)\n\n```css\n/* ❌ Never remove focus outlines */\n*:focus { outline: none; }\n\n/* ✅ Use :focus-visible for keyboard-only focus */\n:focus {\n  outline: none;\n}\n\n:focus-visible {\n  outline: 2px solid #005fcc;\n  outline-offset: 2px;\n}\n\n/* ✅ Or custom focus styles */\nbutton:focus-visible {\n  box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.5);\n}\n```\n\n### Skip links (2.4.1)\n\n```html\n<body>\n  <a href=\"#main-content\" class=\"skip-link\">Skip to main content</a>\n  <header><!-- navigation --></header>\n  <main id=\"main-content\" tabindex=\"-1\">\n    <!-- main content -->\n  </main>\n</body>\n```\n\n```css\n.skip-link {\n  position: absolute;\n  top: -40px;\n  left: 0;\n  background: #000;\n  color: #fff;\n  padding: 8px 16px;\n  z-index: 100;\n}\n\n.skip-link:focus {\n  top: 0;\n}\n```\n\n### Timing (2.2)\n\n```javascript\n// Allow users to extend time limits\nfunction showSessionWarning() {\n  const modal = createModal({\n    title: 'Session Expiring',\n    content: 'Your session will expire in 2 minutes.',\n    actions: [\n      { label: 'Extend session', action: extendSession },\n      { label: 'Log out', action: logout }\n    ],\n    timeout: 120000 // 2 minutes to respond\n  });\n}\n```\n\n### Motion (2.3)\n\n```css\n/* Respect reduced motion preference */\n@media (prefers-reduced-motion: reduce) {\n  *,\n  *::before,\n  *::after {\n    animation-duration: 0.01ms !important;\n    animation-iteration-count: 1 !important;\n    transition-duration: 0.01ms !important;\n    scroll-behavior: auto !important;\n  }\n}\n```\n\n---\n\n## Understandable\n\n### Page language (3.1.1)\n\n```html\n<!-- ❌ No language specified -->\n<html>\n\n<!-- ✅ Language specified -->\n<html lang=\"en\">\n\n<!-- ✅ Language changes within page -->\n<p>The French word for hello is <span lang=\"fr\">bonjour</span>.</p>\n```\n\n### Consistent navigation (3.2.3)\n\n```html\n<!-- Navigation should be consistent across pages -->\n<nav aria-label=\"Main\">\n  <ul>\n    <li><a href=\"/\" aria-current=\"page\">Home</a></li>\n    <li><a href=\"/products\">Products</a></li>\n    <li><a href=\"/about\">About</a></li>\n  </ul>\n</nav>\n```\n\n### Form labels (3.3.2)\n\n```html\n<!-- ❌ No label association -->\n<input type=\"email\" placeholder=\"Email\">\n\n<!-- ✅ Explicit label -->\n<label for=\"email\">Email address</label>\n<input type=\"email\" id=\"email\" name=\"email\" \n       autocomplete=\"email\" required>\n\n<!-- ✅ Implicit label -->\n<label>\n  Email address\n  <input type=\"email\" name=\"email\" autocomplete=\"email\" required>\n</label>\n\n<!-- ✅ With instructions -->\n<label for=\"password\">Password</label>\n<input type=\"password\" id=\"password\" \n       aria-describedby=\"password-requirements\">\n<p id=\"password-requirements\">\n  Must be at least 8 characters with one number.\n</p>\n```\n\n### Error handling (3.3.1, 3.3.3)\n\n```html\n<!-- Announce errors to screen readers -->\n<form novalidate>\n  <div class=\"field\" aria-live=\"polite\">\n    <label for=\"email\">Email</label>\n    <input type=\"email\" id=\"email\" \n           aria-invalid=\"true\"\n           aria-describedby=\"email-error\">\n    <p id=\"email-error\" class=\"error\" role=\"alert\">\n      Please enter a valid email address (e.g., name@example.com)\n    </p>\n  </div>\n</form>\n```\n\n```javascript\n// Focus first error on submit\nform.addEventListener('submit', (e) => {\n  const firstError = form.querySelector('[aria-invalid=\"true\"]');\n  if (firstError) {\n    e.preventDefault();\n    firstError.focus();\n    \n    // Announce error summary\n    const errorSummary = document.getElementById('error-summary');\n    errorSummary.textContent = `${errors.length} errors found. Please fix them and try again.`;\n    errorSummary.focus();\n  }\n});\n```\n\n---\n\n## Robust\n\n### Valid HTML (4.1.1)\n\n```html\n<!-- ❌ Duplicate IDs -->\n<div id=\"content\">...</div>\n<div id=\"content\">...</div>\n\n<!-- ❌ Invalid nesting -->\n<a href=\"/\"><button>Click</button></a>\n\n<!-- ✅ Unique IDs -->\n<div id=\"main-content\">...</div>\n<div id=\"sidebar-content\">...</div>\n\n<!-- ✅ Proper nesting -->\n<a href=\"/\" class=\"button-link\">Click</a>\n```\n\n### ARIA usage (4.1.2)\n\n**Prefer native elements:**\n```html\n<!-- ❌ ARIA role on div -->\n<div role=\"button\" tabindex=\"0\">Click me</div>\n\n<!-- ✅ Native button -->\n<button>Click me</button>\n\n<!-- ❌ ARIA checkbox -->\n<div role=\"checkbox\" aria-checked=\"false\">Option</div>\n\n<!-- ✅ Native checkbox -->\n<label><input type=\"checkbox\"> Option</label>\n```\n\n**When ARIA is needed:**\n```html\n<!-- Custom tabs component -->\n<div role=\"tablist\" aria-label=\"Product information\">\n  <button role=\"tab\" id=\"tab-1\" aria-selected=\"true\" \n          aria-controls=\"panel-1\">Description</button>\n  <button role=\"tab\" id=\"tab-2\" aria-selected=\"false\" \n          aria-controls=\"panel-2\" tabindex=\"-1\">Reviews</button>\n</div>\n<div role=\"tabpanel\" id=\"panel-1\" aria-labelledby=\"tab-1\">\n  <!-- Panel content -->\n</div>\n<div role=\"tabpanel\" id=\"panel-2\" aria-labelledby=\"tab-2\" hidden>\n  <!-- Panel content -->\n</div>\n```\n\n### Live regions (4.1.3)\n\n```html\n<!-- Status updates -->\n<div aria-live=\"polite\" aria-atomic=\"true\" class=\"status\">\n  <!-- Content updates announced to screen readers -->\n</div>\n\n<!-- Urgent alerts -->\n<div role=\"alert\" aria-live=\"assertive\">\n  <!-- Interrupts current announcement -->\n</div>\n```\n\n```javascript\n// Announce dynamic content changes\nfunction showNotification(message, type = 'polite') {\n  const container = document.getElementById(`${type}-announcer`);\n  container.textContent = ''; // Clear first\n  requestAnimationFrame(() => {\n    container.textContent = message;\n  });\n}\n```\n\n---\n\n## Testing checklist\n\n### Automated testing\n```bash\n# Lighthouse accessibility audit\nnpx lighthouse https://example.com --only-categories=accessibility\n\n# axe-core\nnpm install @axe-core/cli -g\naxe https://example.com\n```\n\n### Manual testing\n\n- [ ] **Keyboard navigation:** Tab through entire page, use Enter/Space to activate\n- [ ] **Screen reader:** Test with VoiceOver (Mac), NVDA (Windows), or TalkBack (Android)\n- [ ] **Zoom:** Content usable at 200% zoom\n- [ ] **High contrast:** Test with Windows High Contrast Mode\n- [ ] **Reduced motion:** Test with `prefers-reduced-motion: reduce`\n- [ ] **Focus order:** Logical and follows visual order\n\n### Screen reader commands\n\n| Action | VoiceOver (Mac) | NVDA (Windows) |\n|--------|-----------------|----------------|\n| Start/Stop | ⌘ + F5 | Ctrl + Alt + N |\n| Next item | VO + → | ↓ |\n| Previous item | VO + ← | ↑ |\n| Activate | VO + Space | Enter |\n| Headings list | VO + U, then arrows | H / Shift + H |\n| Links list | VO + U | K / Shift + K |\n\n---\n\n## Common issues by impact\n\n### Critical (fix immediately)\n1. Missing form labels\n2. Missing image alt text\n3. Insufficient color contrast\n4. Keyboard traps\n5. No focus indicators\n\n### Serious (fix before launch)\n1. Missing page language\n2. Missing heading structure\n3. Non-descriptive link text\n4. Auto-playing media\n5. Missing skip links\n\n### Moderate (fix soon)\n1. Missing ARIA labels on icons\n2. Inconsistent navigation\n3. Missing error identification\n4. Timing without controls\n5. Missing landmark regions\n\n## References\n\n- [WCAG 2.1 Quick Reference](https://www.w3.org/WAI/WCAG21/quickref/)\n- [WAI-ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/)\n- [Deque axe Rules](https://dequeuniversity.com/rules/axe/)\n- [Web Quality Audit](../web-quality-audit/SKILL.md)\n","src/resources/skills/accessibility/references/WCAG.md":"# WCAG 2.1 Quick Reference\n\n## Success criteria by level\n\n### Level A (minimum)\n\n| Criterion | Description |\n|-----------|-------------|\n| **1.1.1** Non-text Content | All images, icons have text alternatives |\n| **1.2.1** Audio-only/Video-only | Provide transcript or audio description |\n| **1.2.2** Captions | Video with audio has captions |\n| **1.2.3** Audio Description | Video has audio description |\n| **1.3.1** Info and Relationships | Information conveyed through presentation is available programmatically |\n| **1.3.2** Meaningful Sequence | Reading order is logical |\n| **1.3.3** Sensory Characteristics | Instructions don't rely solely on shape, color, size, location, orientation, or sound |\n| **1.4.1** Use of Color | Color is not the only visual means of conveying information |\n| **1.4.2** Audio Control | Audio playing automatically can be paused/stopped |\n| **2.1.1** Keyboard | All functionality available via keyboard |\n| **2.1.2** No Keyboard Trap | Keyboard focus can be moved away from any component |\n| **2.1.4** Character Key Shortcuts | Single-key shortcuts can be turned off or remapped |\n| **2.2.1** Timing Adjustable | Time limits can be extended |\n| **2.2.2** Pause, Stop, Hide | Moving/blinking content can be paused |\n| **2.3.1** Three Flashes | Nothing flashes more than 3 times per second |\n| **2.4.1** Bypass Blocks | Skip link or landmark navigation available |\n| **2.4.2** Page Titled | Pages have descriptive titles |\n| **2.4.3** Focus Order | Focus order preserves meaning |\n| **2.4.4** Link Purpose | Link purpose clear from link text or context |\n| **2.5.1** Pointer Gestures | Multi-point gestures have single-pointer alternatives |\n| **2.5.2** Pointer Cancellation | Down-event doesn't trigger action (use up-event or click) |\n| **2.5.3** Label in Name | Accessible name contains visible label text |\n| **2.5.4** Motion Actuation | Motion-triggered functions have alternatives |\n| **3.1.1** Language of Page | Default language specified in HTML |\n| **3.2.1** On Focus | Focus doesn't trigger unexpected changes |\n| **3.2.2** On Input | Input doesn't trigger unexpected changes |\n| **3.3.1** Error Identification | Input errors clearly described |\n| **3.3.2** Labels or Instructions | Form inputs have labels or instructions |\n| **4.1.1** Parsing | HTML is well-formed (no duplicate IDs, proper nesting) |\n| **4.1.2** Name, Role, Value | UI components have accessible names and correct roles |\n\n### Level AA (standard)\n\n| Criterion | Description |\n|-----------|-------------|\n| **1.2.4** Captions (Live) | Live audio has captions |\n| **1.2.5** Audio Description | Pre-recorded video has audio description |\n| **1.3.4** Orientation | Content doesn't restrict orientation |\n| **1.3.5** Identify Input Purpose | Input purpose can be programmatically determined |\n| **1.4.3** Contrast (Minimum) | 4.5:1 for normal text, 3:1 for large text |\n| **1.4.4** Resize Text | Text can be resized to 200% without loss of functionality |\n| **1.4.5** Images of Text | Text used instead of images of text |\n| **1.4.10** Reflow | Content reflows at 320px width without horizontal scroll |\n| **1.4.11** Non-text Contrast | UI components have 3:1 contrast |\n| **1.4.12** Text Spacing | Content adapts to text spacing changes |\n| **1.4.13** Content on Hover/Focus | Additional content is dismissible, hoverable, persistent |\n| **2.4.5** Multiple Ways | Multiple ways to find pages |\n| **2.4.6** Headings and Labels | Headings and labels are descriptive |\n| **2.4.7** Focus Visible | Focus indicator is visible |\n| **3.1.2** Language of Parts | Language changes are marked |\n| **3.2.3** Consistent Navigation | Navigation is consistent across pages |\n| **3.2.4** Consistent Identification | Same functionality uses same labels |\n| **3.3.3** Error Suggestion | Error corrections suggested when known |\n| **3.3.4** Error Prevention (Legal) | Actions can be reversed or confirmed |\n| **4.1.3** Status Messages | Status messages announced to screen readers |\n\n### Level AAA (enhanced)\n\n| Criterion | Description |\n|-----------|-------------|\n| **1.4.6** Contrast (Enhanced) | 7:1 for normal text, 4.5:1 for large text |\n| **1.4.8** Visual Presentation | Foreground/background colors can be selected |\n| **1.4.9** Images of Text (No Exception) | No images of text |\n| **2.1.3** Keyboard (No Exception) | All functionality keyboard accessible |\n| **2.2.3** No Timing | No time limits |\n| **2.2.4** Interruptions | Interruptions can be postponed |\n| **2.2.5** Re-authenticating | Data preserved on re-authentication |\n| **2.2.6** Timeouts | Users warned about data loss from inactivity |\n| **2.3.2** Three Flashes | No content flashes more than 3 times |\n| **2.3.3** Animation from Interactions | Motion animation can be disabled |\n| **2.4.8** Location | User location within site is available |\n| **2.4.9** Link Purpose (Link Only) | Link purpose clear from link text alone |\n| **2.4.10** Section Headings | Sections have headings |\n| **3.1.3** Unusual Words | Definitions available for unusual words |\n| **3.1.4** Abbreviations | Abbreviations expanded |\n| **3.1.5** Reading Level | Alternative content for complex text |\n| **3.1.6** Pronunciation | Pronunciation available where needed |\n| **3.2.5** Change on Request | Changes initiated only by user |\n| **3.3.5** Help | Context-sensitive help available |\n| **3.3.6** Error Prevention (All) | All form submissions can be reviewed |\n\n## Common ARIA patterns\n\n### Buttons\n```html\n<button>Label</button>\n<!-- or -->\n<button aria-label=\"Close dialog\">×</button>\n```\n\n### Links\n```html\n<a href=\"/page\">Descriptive link text</a>\n<!-- External links -->\n<a href=\"https://external.com\" target=\"_blank\" rel=\"noopener\">\n  External site\n  <span class=\"visually-hidden\">(opens in new tab)</span>\n</a>\n```\n\n### Form fields\n```html\n<label for=\"email\">Email address</label>\n<input type=\"email\" id=\"email\" aria-describedby=\"email-hint\">\n<p id=\"email-hint\">We'll never share your email.</p>\n```\n\n### Error states\n```html\n<label for=\"email\">Email</label>\n<input type=\"email\" id=\"email\" aria-invalid=\"true\" aria-describedby=\"email-error\">\n<p id=\"email-error\" role=\"alert\">Please enter a valid email address.</p>\n```\n\n### Navigation\n```html\n<nav aria-label=\"Main\">\n  <ul>\n    <li><a href=\"/\" aria-current=\"page\">Home</a></li>\n    <li><a href=\"/about\">About</a></li>\n  </ul>\n</nav>\n```\n\n### Modals\n```html\n<div role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"dialog-title\">\n  <h2 id=\"dialog-title\">Confirm Action</h2>\n  <!-- content -->\n</div>\n```\n\n### Live regions\n```html\n<!-- Polite (waits for pause in speech) -->\n<div aria-live=\"polite\">Status update here</div>\n\n<!-- Assertive (interrupts immediately) -->\n<div aria-live=\"assertive\" role=\"alert\">Error message here</div>\n\n<!-- Status (polite, implicit) -->\n<div role=\"status\">Loading complete</div>\n```\n\n## Testing tools\n\n| Tool | Type | URL |\n|------|------|-----|\n| axe DevTools | Browser extension | [deque.com/axe](https://www.deque.com/axe/) |\n| WAVE | Browser extension | [wave.webaim.org](https://wave.webaim.org/) |\n| Lighthouse | Built into Chrome | DevTools → Lighthouse |\n| NVDA | Screen reader (Windows) | [nvaccess.org](https://www.nvaccess.org/) |\n| VoiceOver | Screen reader (Mac) | Built into macOS |\n| Colour Contrast Analyser | Desktop app | [tpgi.com](https://www.tpgi.com/color-contrast-checker/) |\n","src/resources/skills/agent-browser/SKILL.md":"---\nname: agent-browser\ndescription: Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to \"open a website\", \"fill out a form\", \"click a button\", \"take a screenshot\", \"scrape data from a page\", \"test this web app\", \"login to a site\", \"automate browser actions\", or any task requiring programmatic web interaction.\nallowed-tools: Bash(npx agent-browser:*), Bash(agent-browser:*)\n---\n\n# Browser Automation with agent-browser\n\n## Core Workflow\n\nEvery browser automation follows this pattern:\n\n1. **Navigate**: `agent-browser open <url>`\n2. **Snapshot**: `agent-browser snapshot -i` (get element refs like `@e1`, `@e2`)\n3. **Interact**: Use refs to click, fill, select\n4. **Re-snapshot**: After navigation or DOM changes, get fresh refs\n\n```bash\nagent-browser open https://example.com/form\nagent-browser snapshot -i\n# Output: @e1 [input type=\"email\"], @e2 [input type=\"password\"], @e3 [button] \"Submit\"\n\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\nagent-browser click @e3\nagent-browser wait --load networkidle\nagent-browser snapshot -i  # Check result\n```\n\n## Command Chaining\n\nCommands can be chained with `&&` in a single shell invocation. The browser persists between commands via a background daemon, so chaining is safe and more efficient than separate calls.\n\n```bash\n# Chain open + wait + snapshot in one call\nagent-browser open https://example.com && agent-browser wait --load networkidle && agent-browser snapshot -i\n\n# Chain multiple interactions\nagent-browser fill @e1 \"user@example.com\" && agent-browser fill @e2 \"password123\" && agent-browser click @e3\n\n# Navigate and capture\nagent-browser open https://example.com && agent-browser wait --load networkidle && agent-browser screenshot page.png\n```\n\n**When to chain:** Use `&&` when you don't need to read the output of an intermediate command before proceeding (e.g., open + wait + screenshot). Run commands separately when you need to parse the output first (e.g., snapshot to discover refs, then interact using those refs).\n\n## Essential Commands\n\n```bash\n# Navigation\nagent-browser open <url>              # Navigate (aliases: goto, navigate)\nagent-browser close                   # Close browser\n\n# Snapshot\nagent-browser snapshot -i             # Interactive elements with refs (recommended)\nagent-browser snapshot -i -C          # Include cursor-interactive elements (divs with onclick, cursor:pointer)\nagent-browser snapshot -s \"#selector\" # Scope to CSS selector\n\n# Interaction (use @refs from snapshot)\nagent-browser click @e1               # Click element\nagent-browser click @e1 --new-tab     # Click and open in new tab\nagent-browser fill @e2 \"text\"         # Clear and type text\nagent-browser type @e2 \"text\"         # Type without clearing\nagent-browser select @e1 \"option\"     # Select dropdown option\nagent-browser check @e1               # Check checkbox\nagent-browser press Enter             # Press key\nagent-browser keyboard type \"text\"    # Type at current focus (no selector)\nagent-browser keyboard inserttext \"text\"  # Insert without key events\nagent-browser scroll down 500         # Scroll page\nagent-browser scroll down 500 --selector \"div.content\"  # Scroll within a specific container\n\n# Get information\nagent-browser get text @e1            # Get element text\nagent-browser get url                 # Get current URL\nagent-browser get title               # Get page title\n\n# Wait\nagent-browser wait @e1                # Wait for element\nagent-browser wait --load networkidle # Wait for network idle\nagent-browser wait --url \"**/page\"    # Wait for URL pattern\nagent-browser wait 2000               # Wait milliseconds\n\n# Downloads\nagent-browser download @e1 ./file.pdf          # Click element to trigger download\nagent-browser wait --download ./output.zip     # Wait for any download to complete\nagent-browser --download-path ./downloads open <url>  # Set default download directory\n\n# Capture\nagent-browser screenshot              # Screenshot to temp dir\nagent-browser screenshot --full       # Full page screenshot\nagent-browser screenshot --annotate   # Annotated screenshot with numbered element labels\nagent-browser pdf output.pdf          # Save as PDF\n\n# Diff (compare page states)\nagent-browser diff snapshot                          # Compare current vs last snapshot\nagent-browser diff snapshot --baseline before.txt    # Compare current vs saved file\nagent-browser diff screenshot --baseline before.png  # Visual pixel diff\nagent-browser diff url <url1> <url2>                 # Compare two pages\nagent-browser diff url <url1> <url2> --wait-until networkidle  # Custom wait strategy\nagent-browser diff url <url1> <url2> --selector \"#main\"  # Scope to element\n```\n\n## Common Patterns\n\n### Form Submission\n\n```bash\nagent-browser open https://example.com/signup\nagent-browser snapshot -i\nagent-browser fill @e1 \"Jane Doe\"\nagent-browser fill @e2 \"jane@example.com\"\nagent-browser select @e3 \"California\"\nagent-browser check @e4\nagent-browser click @e5\nagent-browser wait --load networkidle\n```\n\n### Authentication with Auth Vault (Recommended)\n\n```bash\n# Save credentials once (encrypted with AGENT_BROWSER_ENCRYPTION_KEY)\n# Recommended: pipe password via stdin to avoid shell history exposure\necho \"pass\" | agent-browser auth save github --url https://github.com/login --username user --password-stdin\n\n# Login using saved profile (LLM never sees password)\nagent-browser auth login github\n\n# List/show/delete profiles\nagent-browser auth list\nagent-browser auth show github\nagent-browser auth delete github\n```\n\n### Authentication with State Persistence\n\n```bash\n# Login once and save state\nagent-browser open https://app.example.com/login\nagent-browser snapshot -i\nagent-browser fill @e1 \"$USERNAME\"\nagent-browser fill @e2 \"$PASSWORD\"\nagent-browser click @e3\nagent-browser wait --url \"**/dashboard\"\nagent-browser state save auth.json\n\n# Reuse in future sessions\nagent-browser state load auth.json\nagent-browser open https://app.example.com/dashboard\n```\n\n### Session Persistence\n\n```bash\n# Auto-save/restore cookies and localStorage across browser restarts\nagent-browser --session-name myapp open https://app.example.com/login\n# ... login flow ...\nagent-browser close  # State auto-saved to ~/.agent-browser/sessions/\n\n# Next time, state is auto-loaded\nagent-browser --session-name myapp open https://app.example.com/dashboard\n\n# Encrypt state at rest\nexport AGENT_BROWSER_ENCRYPTION_KEY=$(openssl rand -hex 32)\nagent-browser --session-name secure open https://app.example.com\n\n# Manage saved states\nagent-browser state list\nagent-browser state show myapp-default.json\nagent-browser state clear myapp\nagent-browser state clean --older-than 7\n```\n\n### Data Extraction\n\n```bash\nagent-browser open https://example.com/products\nagent-browser snapshot -i\nagent-browser get text @e5           # Get specific element text\nagent-browser get text body > page.txt  # Get all page text\n\n# JSON output for parsing\nagent-browser snapshot -i --json\nagent-browser get text @e1 --json\n```\n\n### Parallel Sessions\n\n```bash\nagent-browser --session site1 open https://site-a.com\nagent-browser --session site2 open https://site-b.com\n\nagent-browser --session site1 snapshot -i\nagent-browser --session site2 snapshot -i\n\nagent-browser session list\n```\n\n### Connect to Existing Chrome\n\n```bash\n# Auto-discover running Chrome with remote debugging enabled\nagent-browser --auto-connect open https://example.com\nagent-browser --auto-connect snapshot\n\n# Or with explicit CDP port\nagent-browser --cdp 9222 snapshot\n```\n\n### Color Scheme (Dark Mode)\n\n```bash\n# Persistent dark mode via flag (applies to all pages and new tabs)\nagent-browser --color-scheme dark open https://example.com\n\n# Or via environment variable\nAGENT_BROWSER_COLOR_SCHEME=dark agent-browser open https://example.com\n\n# Or set during session (persists for subsequent commands)\nagent-browser set media dark\n```\n\n### Visual Browser (Debugging)\n\n```bash\nagent-browser --headed open https://example.com\nagent-browser highlight @e1          # Highlight element\nagent-browser record start demo.webm # Record session\nagent-browser profiler start         # Start Chrome DevTools profiling\nagent-browser profiler stop trace.json # Stop and save profile (path optional)\n```\n\nUse `AGENT_BROWSER_HEADED=1` to enable headed mode via environment variable. Browser extensions work in both headed and headless mode.\n\n### Local Files (PDFs, HTML)\n\n```bash\n# Open local files with file:// URLs\nagent-browser --allow-file-access open file:///path/to/document.pdf\nagent-browser --allow-file-access open file:///path/to/page.html\nagent-browser screenshot output.png\n```\n\n### iOS Simulator (Mobile Safari)\n\n```bash\n# List available iOS simulators\nagent-browser device list\n\n# Launch Safari on a specific device\nagent-browser -p ios --device \"iPhone 16 Pro\" open https://example.com\n\n# Same workflow as desktop - snapshot, interact, re-snapshot\nagent-browser -p ios snapshot -i\nagent-browser -p ios tap @e1          # Tap (alias for click)\nagent-browser -p ios fill @e2 \"text\"\nagent-browser -p ios swipe up         # Mobile-specific gesture\n\n# Take screenshot\nagent-browser -p ios screenshot mobile.png\n\n# Close session (shuts down simulator)\nagent-browser -p ios close\n```\n\n**Requirements:** macOS with Xcode, Appium (`npm install -g appium && appium driver install xcuitest`)\n\n**Real devices:** Works with physical iOS devices if pre-configured. Use `--device \"<UDID>\"` where UDID is from `xcrun xctrace list devices`.\n\n## Security\n\nAll security features are opt-in. By default, agent-browser imposes no restrictions on navigation, actions, or output.\n\n### Content Boundaries (Recommended for AI Agents)\n\nEnable `--content-boundaries` to wrap page-sourced output in markers that help LLMs distinguish tool output from untrusted page content:\n\n```bash\nexport AGENT_BROWSER_CONTENT_BOUNDARIES=1\nagent-browser snapshot\n# Output:\n# --- AGENT_BROWSER_PAGE_CONTENT nonce=<hex> origin=https://example.com ---\n# [accessibility tree]\n# --- END_AGENT_BROWSER_PAGE_CONTENT nonce=<hex> ---\n```\n\n### Domain Allowlist\n\nRestrict navigation to trusted domains. Wildcards like `*.example.com` also match the bare domain `example.com`. Sub-resource requests, WebSocket, and EventSource connections to non-allowed domains are also blocked. Include CDN domains your target pages depend on:\n\n```bash\nexport AGENT_BROWSER_ALLOWED_DOMAINS=\"example.com,*.example.com\"\nagent-browser open https://example.com        # OK\nagent-browser open https://malicious.com       # Blocked\n```\n\n### Action Policy\n\nUse a policy file to gate destructive actions:\n\n```bash\nexport AGENT_BROWSER_ACTION_POLICY=./policy.json\n```\n\nExample `policy.json`:\n```json\n{\"default\": \"deny\", \"allow\": [\"navigate\", \"snapshot\", \"click\", \"scroll\", \"wait\", \"get\"]}\n```\n\nAuth vault operations (`auth login`, etc.) bypass action policy but domain allowlist still applies.\n\n### Output Limits\n\nPrevent context flooding from large pages:\n\n```bash\nexport AGENT_BROWSER_MAX_OUTPUT=50000\n```\n\n## Diffing (Verifying Changes)\n\nUse `diff snapshot` after performing an action to verify it had the intended effect. This compares the current accessibility tree against the last snapshot taken in the session.\n\n```bash\n# Typical workflow: snapshot -> action -> diff\nagent-browser snapshot -i          # Take baseline snapshot\nagent-browser click @e2            # Perform action\nagent-browser diff snapshot        # See what changed (auto-compares to last snapshot)\n```\n\nFor visual regression testing or monitoring:\n\n```bash\n# Save a baseline screenshot, then compare later\nagent-browser screenshot baseline.png\n# ... time passes or changes are made ...\nagent-browser diff screenshot --baseline baseline.png\n\n# Compare staging vs production\nagent-browser diff url https://staging.example.com https://prod.example.com --screenshot\n```\n\n`diff snapshot` output uses `+` for additions and `-` for removals, similar to git diff. `diff screenshot` produces a diff image with changed pixels highlighted in red, plus a mismatch percentage.\n\n## Timeouts and Slow Pages\n\nThe default Playwright timeout is 25 seconds for local browsers. This can be overridden with the `AGENT_BROWSER_DEFAULT_TIMEOUT` environment variable (value in milliseconds). For slow websites or large pages, use explicit waits instead of relying on the default timeout:\n\n```bash\n# Wait for network activity to settle (best for slow pages)\nagent-browser wait --load networkidle\n\n# Wait for a specific element to appear\nagent-browser wait \"#content\"\nagent-browser wait @e1\n\n# Wait for a specific URL pattern (useful after redirects)\nagent-browser wait --url \"**/dashboard\"\n\n# Wait for a JavaScript condition\nagent-browser wait --fn \"document.readyState === 'complete'\"\n\n# Wait a fixed duration (milliseconds) as a last resort\nagent-browser wait 5000\n```\n\nWhen dealing with consistently slow websites, use `wait --load networkidle` after `open` to ensure the page is fully loaded before taking a snapshot. If a specific element is slow to render, wait for it directly with `wait <selector>` or `wait @ref`.\n\n## Session Management and Cleanup\n\nWhen running multiple agents or automations concurrently, always use named sessions to avoid conflicts:\n\n```bash\n# Each agent gets its own isolated session\nagent-browser --session agent1 open site-a.com\nagent-browser --session agent2 open site-b.com\n\n# Check active sessions\nagent-browser session list\n```\n\nAlways close your browser session when done to avoid leaked processes:\n\n```bash\nagent-browser close                    # Close default session\nagent-browser --session agent1 close   # Close specific session\n```\n\nIf a previous session was not closed properly, the daemon may still be running. Use `agent-browser close` to clean it up before starting new work.\n\n## Ref Lifecycle (Important)\n\nRefs (`@e1`, `@e2`, etc.) are invalidated when the page changes. Always re-snapshot after:\n\n- Clicking links or buttons that navigate\n- Form submissions\n- Dynamic content loading (dropdowns, modals)\n\n```bash\nagent-browser click @e5              # Navigates to new page\nagent-browser snapshot -i            # MUST re-snapshot\nagent-browser click @e1              # Use new refs\n```\n\n## Annotated Screenshots (Vision Mode)\n\nUse `--annotate` to take a screenshot with numbered labels overlaid on interactive elements. Each label `[N]` maps to ref `@eN`. This also caches refs, so you can interact with elements immediately without a separate snapshot.\n\n```bash\nagent-browser screenshot --annotate\n# Output includes the image path and a legend:\n#   [1] @e1 button \"Submit\"\n#   [2] @e2 link \"Home\"\n#   [3] @e3 textbox \"Email\"\nagent-browser click @e2              # Click using ref from annotated screenshot\n```\n\nUse annotated screenshots when:\n- The page has unlabeled icon buttons or visual-only elements\n- You need to verify visual layout or styling\n- Canvas or chart elements are present (invisible to text snapshots)\n- You need spatial reasoning about element positions\n\n## Semantic Locators (Alternative to Refs)\n\nWhen refs are unavailable or unreliable, use semantic locators:\n\n```bash\nagent-browser find text \"Sign In\" click\nagent-browser find label \"Email\" fill \"user@test.com\"\nagent-browser find role button click --name \"Submit\"\nagent-browser find placeholder \"Search\" type \"query\"\nagent-browser find testid \"submit-btn\" click\n```\n\n## JavaScript Evaluation (eval)\n\nUse `eval` to run JavaScript in the browser context. **Shell quoting can corrupt complex expressions** -- use `--stdin` or `-b` to avoid issues.\n\n```bash\n# Simple expressions work with regular quoting\nagent-browser eval 'document.title'\nagent-browser eval 'document.querySelectorAll(\"img\").length'\n\n# Complex JS: use --stdin with heredoc (RECOMMENDED)\nagent-browser eval --stdin <<'EVALEOF'\nJSON.stringify(\n  Array.from(document.querySelectorAll(\"img\"))\n    .filter(i => !i.alt)\n    .map(i => ({ src: i.src.split(\"/\").pop(), width: i.width }))\n)\nEVALEOF\n\n# Alternative: base64 encoding (avoids all shell escaping issues)\nagent-browser eval -b \"$(echo -n 'Array.from(document.querySelectorAll(\"a\")).map(a => a.href)' | base64)\"\n```\n\n**Why this matters:** When the shell processes your command, inner double quotes, `!` characters (history expansion), backticks, and `$()` can all corrupt the JavaScript before it reaches agent-browser. The `--stdin` and `-b` flags bypass shell interpretation entirely.\n\n**Rules of thumb:**\n- Single-line, no nested quotes -> regular `eval 'expression'` with single quotes is fine\n- Nested quotes, arrow functions, template literals, or multiline -> use `eval --stdin <<'EVALEOF'`\n- Programmatic/generated scripts -> use `eval -b` with base64\n\n## Configuration File\n\nCreate `agent-browser.json` in the project root for persistent settings:\n\n```json\n{\n  \"headed\": true,\n  \"proxy\": \"http://localhost:8080\",\n  \"profile\": \"./browser-data\"\n}\n```\n\nPriority (lowest to highest): `~/.agent-browser/config.json` < `./agent-browser.json` < env vars < CLI flags. Use `--config <path>` or `AGENT_BROWSER_CONFIG` env var for a custom config file (exits with error if missing/invalid). All CLI options map to camelCase keys (e.g., `--executable-path` -> `\"executablePath\"`). Boolean flags accept `true`/`false` values (e.g., `--headed false` overrides config). Extensions from user and project configs are merged, not replaced.\n\n## Deep-Dive Documentation\n\n| Reference | When to Use |\n|-----------|-------------|\n| [references/commands.md](references/commands.md) | Full command reference with all options |\n| [references/snapshot-refs.md](references/snapshot-refs.md) | Ref lifecycle, invalidation rules, troubleshooting |\n| [references/session-management.md](references/session-management.md) | Parallel sessions, state persistence, concurrent scraping |\n| [references/authentication.md](references/authentication.md) | Login flows, OAuth, 2FA handling, state reuse |\n| [references/video-recording.md](references/video-recording.md) | Recording workflows for debugging and documentation |\n| [references/profiling.md](references/profiling.md) | Chrome DevTools profiling for performance analysis |\n| [references/proxy-support.md](references/proxy-support.md) | Proxy configuration, geo-testing, rotating proxies |\n\n## Experimental: Native Mode\n\nagent-browser has an experimental native Rust daemon that communicates with Chrome directly via CDP, bypassing Node.js and Playwright entirely. It is opt-in and not recommended for production use yet.\n\n```bash\n# Enable via flag\nagent-browser --native open example.com\n\n# Enable via environment variable (avoids passing --native every time)\nexport AGENT_BROWSER_NATIVE=1\nagent-browser open example.com\n```\n\nThe native daemon supports Chromium and Safari (via WebDriver). Firefox and WebKit are not yet supported. All core commands (navigate, snapshot, click, fill, screenshot, cookies, storage, tabs, eval, etc.) work identically in native mode. Use `agent-browser close` before switching between native and default mode within the same session.\n\n## Ready-to-Use Templates\n\n| Template | Description |\n|----------|-------------|\n| [templates/form-automation.sh](templates/form-automation.sh) | Form filling with validation |\n| [templates/authenticated-session.sh](templates/authenticated-session.sh) | Login once, reuse state |\n| [templates/capture-workflow.sh](templates/capture-workflow.sh) | Content extraction with screenshots |\n\n```bash\n./templates/form-automation.sh https://example.com/form\n./templates/authenticated-session.sh https://app.example.com/login\n./templates/capture-workflow.sh https://example.com ./output\n```\n","src/resources/skills/agent-browser/references/authentication.md":"# Authentication Patterns\n\nLogin flows, session persistence, OAuth, 2FA, and authenticated browsing.\n\n**Related**: [session-management.md](session-management.md) for state persistence details, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Login Flow](#basic-login-flow)\n- [Saving Authentication State](#saving-authentication-state)\n- [Restoring Authentication](#restoring-authentication)\n- [OAuth / SSO Flows](#oauth--sso-flows)\n- [Two-Factor Authentication](#two-factor-authentication)\n- [HTTP Basic Auth](#http-basic-auth)\n- [Cookie-Based Auth](#cookie-based-auth)\n- [Token Refresh Handling](#token-refresh-handling)\n- [Security Best Practices](#security-best-practices)\n\n## Basic Login Flow\n\n```bash\n# Navigate to login page\nagent-browser open https://app.example.com/login\nagent-browser wait --load networkidle\n\n# Get form elements\nagent-browser snapshot -i\n# Output: @e1 [input type=\"email\"], @e2 [input type=\"password\"], @e3 [button] \"Sign In\"\n\n# Fill credentials\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\n\n# Submit\nagent-browser click @e3\nagent-browser wait --load networkidle\n\n# Verify login succeeded\nagent-browser get url  # Should be dashboard, not login\n```\n\n## Saving Authentication State\n\nAfter logging in, save state for reuse:\n\n```bash\n# Login first (see above)\nagent-browser open https://app.example.com/login\nagent-browser snapshot -i\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\nagent-browser click @e3\nagent-browser wait --url \"**/dashboard\"\n\n# Save authenticated state\nagent-browser state save ./auth-state.json\n```\n\n## Restoring Authentication\n\nSkip login by loading saved state:\n\n```bash\n# Load saved auth state\nagent-browser state load ./auth-state.json\n\n# Navigate directly to protected page\nagent-browser open https://app.example.com/dashboard\n\n# Verify authenticated\nagent-browser snapshot -i\n```\n\n## OAuth / SSO Flows\n\nFor OAuth redirects:\n\n```bash\n# Start OAuth flow\nagent-browser open https://app.example.com/auth/google\n\n# Handle redirects automatically\nagent-browser wait --url \"**/accounts.google.com**\"\nagent-browser snapshot -i\n\n# Fill Google credentials\nagent-browser fill @e1 \"user@gmail.com\"\nagent-browser click @e2  # Next button\nagent-browser wait 2000\nagent-browser snapshot -i\nagent-browser fill @e3 \"password\"\nagent-browser click @e4  # Sign in\n\n# Wait for redirect back\nagent-browser wait --url \"**/app.example.com**\"\nagent-browser state save ./oauth-state.json\n```\n\n## Two-Factor Authentication\n\nHandle 2FA with manual intervention:\n\n```bash\n# Login with credentials\nagent-browser open https://app.example.com/login --headed  # Show browser\nagent-browser snapshot -i\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\nagent-browser click @e3\n\n# Wait for user to complete 2FA manually\necho \"Complete 2FA in the browser window...\"\nagent-browser wait --url \"**/dashboard\" --timeout 120000\n\n# Save state after 2FA\nagent-browser state save ./2fa-state.json\n```\n\n## HTTP Basic Auth\n\nFor sites using HTTP Basic Authentication:\n\n```bash\n# Set credentials before navigation\nagent-browser set credentials username password\n\n# Navigate to protected resource\nagent-browser open https://protected.example.com/api\n```\n\n## Cookie-Based Auth\n\nManually set authentication cookies:\n\n```bash\n# Set auth cookie\nagent-browser cookies set session_token \"abc123xyz\"\n\n# Navigate to protected page\nagent-browser open https://app.example.com/dashboard\n```\n\n## Token Refresh Handling\n\nFor sessions with expiring tokens:\n\n```bash\n#!/bin/bash\n# Wrapper that handles token refresh\n\nSTATE_FILE=\"./auth-state.json\"\n\n# Try loading existing state\nif [[ -f \"$STATE_FILE\" ]]; then\n    agent-browser state load \"$STATE_FILE\"\n    agent-browser open https://app.example.com/dashboard\n\n    # Check if session is still valid\n    URL=$(agent-browser get url)\n    if [[ \"$URL\" == *\"/login\"* ]]; then\n        echo \"Session expired, re-authenticating...\"\n        # Perform fresh login\n        agent-browser snapshot -i\n        agent-browser fill @e1 \"$USERNAME\"\n        agent-browser fill @e2 \"$PASSWORD\"\n        agent-browser click @e3\n        agent-browser wait --url \"**/dashboard\"\n        agent-browser state save \"$STATE_FILE\"\n    fi\nelse\n    # First-time login\n    agent-browser open https://app.example.com/login\n    # ... login flow ...\nfi\n```\n\n## Security Best Practices\n\n1. **Never commit state files** - They contain session tokens\n   ```bash\n   echo \"*.auth-state.json\" >> .gitignore\n   ```\n\n2. **Use environment variables for credentials**\n   ```bash\n   agent-browser fill @e1 \"$APP_USERNAME\"\n   agent-browser fill @e2 \"$APP_PASSWORD\"\n   ```\n\n3. **Clean up after automation**\n   ```bash\n   agent-browser cookies clear\n   rm -f ./auth-state.json\n   ```\n\n4. **Use short-lived sessions for CI/CD**\n   ```bash\n   # Don't persist state in CI\n   agent-browser open https://app.example.com/login\n   # ... login and perform actions ...\n   agent-browser close  # Session ends, nothing persisted\n   ```\n","src/resources/skills/agent-browser/references/commands.md":"# Command Reference\n\nComplete reference for all agent-browser commands. For quick start and common patterns, see SKILL.md.\n\n## Navigation\n\n```bash\nagent-browser open <url>      # Navigate to URL (aliases: goto, navigate)\n                              # Supports: https://, http://, file://, about:, data://\n                              # Auto-prepends https:// if no protocol given\nagent-browser back            # Go back\nagent-browser forward         # Go forward\nagent-browser reload          # Reload page\nagent-browser close           # Close browser (aliases: quit, exit)\nagent-browser connect 9222    # Connect to browser via CDP port\n```\n\n## Snapshot (page analysis)\n\n```bash\nagent-browser snapshot            # Full accessibility tree\nagent-browser snapshot -i         # Interactive elements only (recommended)\nagent-browser snapshot -c         # Compact output\nagent-browser snapshot -d 3       # Limit depth to 3\nagent-browser snapshot -s \"#main\" # Scope to CSS selector\n```\n\n## Interactions (use @refs from snapshot)\n\n```bash\nagent-browser click @e1           # Click\nagent-browser click @e1 --new-tab # Click and open in new tab\nagent-browser dblclick @e1        # Double-click\nagent-browser focus @e1           # Focus element\nagent-browser fill @e2 \"text\"     # Clear and type\nagent-browser type @e2 \"text\"     # Type without clearing\nagent-browser press Enter         # Press key (alias: key)\nagent-browser press Control+a     # Key combination\nagent-browser keydown Shift       # Hold key down\nagent-browser keyup Shift         # Release key\nagent-browser hover @e1           # Hover\nagent-browser check @e1           # Check checkbox\nagent-browser uncheck @e1         # Uncheck checkbox\nagent-browser select @e1 \"value\"  # Select dropdown option\nagent-browser select @e1 \"a\" \"b\"  # Select multiple options\nagent-browser scroll down 500     # Scroll page (default: down 300px)\nagent-browser scrollintoview @e1  # Scroll element into view (alias: scrollinto)\nagent-browser drag @e1 @e2        # Drag and drop\nagent-browser upload @e1 file.pdf # Upload files\n```\n\n## Get Information\n\n```bash\nagent-browser get text @e1        # Get element text\nagent-browser get html @e1        # Get innerHTML\nagent-browser get value @e1       # Get input value\nagent-browser get attr @e1 href   # Get attribute\nagent-browser get title           # Get page title\nagent-browser get url             # Get current URL\nagent-browser get count \".item\"   # Count matching elements\nagent-browser get box @e1         # Get bounding box\nagent-browser get styles @e1      # Get computed styles (font, color, bg, etc.)\n```\n\n## Check State\n\n```bash\nagent-browser is visible @e1      # Check if visible\nagent-browser is enabled @e1      # Check if enabled\nagent-browser is checked @e1      # Check if checked\n```\n\n## Screenshots and PDF\n\n```bash\nagent-browser screenshot          # Save to temporary directory\nagent-browser screenshot path.png # Save to specific path\nagent-browser screenshot --full   # Full page\nagent-browser pdf output.pdf      # Save as PDF\n```\n\n## Video Recording\n\n```bash\nagent-browser record start ./demo.webm    # Start recording\nagent-browser click @e1                   # Perform actions\nagent-browser record stop                 # Stop and save video\nagent-browser record restart ./take2.webm # Stop current + start new\n```\n\n## Wait\n\n```bash\nagent-browser wait @e1                     # Wait for element\nagent-browser wait 2000                    # Wait milliseconds\nagent-browser wait --text \"Success\"        # Wait for text (or -t)\nagent-browser wait --url \"**/dashboard\"    # Wait for URL pattern (or -u)\nagent-browser wait --load networkidle      # Wait for network idle (or -l)\nagent-browser wait --fn \"window.ready\"     # Wait for JS condition (or -f)\n```\n\n## Mouse Control\n\n```bash\nagent-browser mouse move 100 200      # Move mouse\nagent-browser mouse down left         # Press button\nagent-browser mouse up left           # Release button\nagent-browser mouse wheel 100         # Scroll wheel\n```\n\n## Semantic Locators (alternative to refs)\n\n```bash\nagent-browser find role button click --name \"Submit\"\nagent-browser find text \"Sign In\" click\nagent-browser find text \"Sign In\" click --exact      # Exact match only\nagent-browser find label \"Email\" fill \"user@test.com\"\nagent-browser find placeholder \"Search\" type \"query\"\nagent-browser find alt \"Logo\" click\nagent-browser find title \"Close\" click\nagent-browser find testid \"submit-btn\" click\nagent-browser find first \".item\" click\nagent-browser find last \".item\" click\nagent-browser find nth 2 \"a\" hover\n```\n\n## Browser Settings\n\n```bash\nagent-browser set viewport 1920 1080          # Set viewport size\nagent-browser set device \"iPhone 14\"          # Emulate device\nagent-browser set geo 37.7749 -122.4194       # Set geolocation (alias: geolocation)\nagent-browser set offline on                  # Toggle offline mode\nagent-browser set headers '{\"X-Key\":\"v\"}'     # Extra HTTP headers\nagent-browser set credentials user pass       # HTTP basic auth (alias: auth)\nagent-browser set media dark                  # Emulate color scheme\nagent-browser set media light reduced-motion  # Light mode + reduced motion\n```\n\n## Cookies and Storage\n\n```bash\nagent-browser cookies                     # Get all cookies\nagent-browser cookies set name value      # Set cookie\nagent-browser cookies clear               # Clear cookies\nagent-browser storage local               # Get all localStorage\nagent-browser storage local key           # Get specific key\nagent-browser storage local set k v       # Set value\nagent-browser storage local clear         # Clear all\n```\n\n## Network\n\n```bash\nagent-browser network route <url>              # Intercept requests\nagent-browser network route <url> --abort      # Block requests\nagent-browser network route <url> --body '{}'  # Mock response\nagent-browser network unroute [url]            # Remove routes\nagent-browser network requests                 # View tracked requests\nagent-browser network requests --filter api    # Filter requests\n```\n\n## Tabs and Windows\n\n```bash\nagent-browser tab                 # List tabs\nagent-browser tab new [url]       # New tab\nagent-browser tab 2               # Switch to tab by index\nagent-browser tab close           # Close current tab\nagent-browser tab close 2         # Close tab by index\nagent-browser window new          # New window\n```\n\n## Frames\n\n```bash\nagent-browser frame \"#iframe\"     # Switch to iframe\nagent-browser frame main          # Back to main frame\n```\n\n## Dialogs\n\n```bash\nagent-browser dialog accept [text]  # Accept dialog\nagent-browser dialog dismiss        # Dismiss dialog\n```\n\n## JavaScript\n\n```bash\nagent-browser eval \"document.title\"          # Simple expressions only\nagent-browser eval -b \"<base64>\"             # Any JavaScript (base64 encoded)\nagent-browser eval --stdin                   # Read script from stdin\n```\n\nUse `-b`/`--base64` or `--stdin` for reliable execution. Shell escaping with nested quotes and special characters is error-prone.\n\n```bash\n# Base64 encode your script, then:\nagent-browser eval -b \"ZG9jdW1lbnQucXVlcnlTZWxlY3RvcignW3NyYyo9Il9uZXh0Il0nKQ==\"\n\n# Or use stdin with heredoc for multiline scripts:\ncat <<'EOF' | agent-browser eval --stdin\nconst links = document.querySelectorAll('a');\nArray.from(links).map(a => a.href);\nEOF\n```\n\n## State Management\n\n```bash\nagent-browser state save auth.json    # Save cookies, storage, auth state\nagent-browser state load auth.json    # Restore saved state\n```\n\n## Global Options\n\n```bash\nagent-browser --session <name> ...    # Isolated browser session\nagent-browser --json ...              # JSON output for parsing\nagent-browser --headed ...            # Show browser window (not headless)\nagent-browser --full ...              # Full page screenshot (-f)\nagent-browser --cdp <port> ...        # Connect via Chrome DevTools Protocol\nagent-browser -p <provider> ...       # Cloud browser provider (--provider)\nagent-browser --proxy <url> ...       # Use proxy server\nagent-browser --proxy-bypass <hosts>  # Hosts to bypass proxy\nagent-browser --headers <json> ...    # HTTP headers scoped to URL's origin\nagent-browser --executable-path <p>   # Custom browser executable\nagent-browser --extension <path> ...  # Load browser extension (repeatable)\nagent-browser --ignore-https-errors   # Ignore SSL certificate errors\nagent-browser --help                  # Show help (-h)\nagent-browser --version               # Show version (-V)\nagent-browser <command> --help        # Show detailed help for a command\n```\n\n## Debugging\n\n```bash\nagent-browser --headed open example.com   # Show browser window\nagent-browser --cdp 9222 snapshot         # Connect via CDP port\nagent-browser connect 9222                # Alternative: connect command\nagent-browser console                     # View console messages\nagent-browser console --clear             # Clear console\nagent-browser errors                      # View page errors\nagent-browser errors --clear              # Clear errors\nagent-browser highlight @e1               # Highlight element\nagent-browser trace start                 # Start recording trace\nagent-browser trace stop trace.zip        # Stop and save trace\nagent-browser profiler start              # Start Chrome DevTools profiling\nagent-browser profiler stop trace.json    # Stop and save profile\n```\n\n## Environment Variables\n\n```bash\nAGENT_BROWSER_SESSION=\"mysession\"            # Default session name\nAGENT_BROWSER_EXECUTABLE_PATH=\"/path/chrome\" # Custom browser path\nAGENT_BROWSER_EXTENSIONS=\"/ext1,/ext2\"       # Comma-separated extension paths\nAGENT_BROWSER_PROVIDER=\"browserbase\"         # Cloud browser provider\nAGENT_BROWSER_STREAM_PORT=\"9223\"             # WebSocket streaming port\nAGENT_BROWSER_HOME=\"/path/to/agent-browser\"  # Custom install location\n```\n","src/resources/skills/agent-browser/references/profiling.md":"# Profiling\n\nCapture Chrome DevTools performance profiles during browser automation for performance analysis.\n\n**Related**: [commands.md](commands.md) for full command reference, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Profiling](#basic-profiling)\n- [Profiler Commands](#profiler-commands)\n- [Categories](#categories)\n- [Use Cases](#use-cases)\n- [Output Format](#output-format)\n- [Viewing Profiles](#viewing-profiles)\n- [Limitations](#limitations)\n\n## Basic Profiling\n\n```bash\n# Start profiling\nagent-browser profiler start\n\n# Perform actions\nagent-browser navigate https://example.com\nagent-browser click \"#button\"\nagent-browser wait 1000\n\n# Stop and save\nagent-browser profiler stop ./trace.json\n```\n\n## Profiler Commands\n\n```bash\n# Start profiling with default categories\nagent-browser profiler start\n\n# Start with custom trace categories\nagent-browser profiler start --categories \"devtools.timeline,v8.execute,blink.user_timing\"\n\n# Stop profiling and save to file\nagent-browser profiler stop ./trace.json\n```\n\n## Categories\n\nThe `--categories` flag accepts a comma-separated list of Chrome trace categories. Default categories include:\n\n- `devtools.timeline` -- standard DevTools performance traces\n- `v8.execute` -- time spent running JavaScript\n- `blink` -- renderer events\n- `blink.user_timing` -- `performance.mark()` / `performance.measure()` calls\n- `latencyInfo` -- input-to-latency tracking\n- `renderer.scheduler` -- task scheduling and execution\n- `toplevel` -- broad-spectrum basic events\n\nSeveral `disabled-by-default-*` categories are also included for detailed timeline, call stack, and V8 CPU profiling data.\n\n## Use Cases\n\n### Diagnosing Slow Page Loads\n\n```bash\nagent-browser profiler start\nagent-browser navigate https://app.example.com\nagent-browser wait --load networkidle\nagent-browser profiler stop ./page-load-profile.json\n```\n\n### Profiling User Interactions\n\n```bash\nagent-browser navigate https://app.example.com\nagent-browser profiler start\nagent-browser click \"#submit\"\nagent-browser wait 2000\nagent-browser profiler stop ./interaction-profile.json\n```\n\n### CI Performance Regression Checks\n\n```bash\n#!/bin/bash\nagent-browser profiler start\nagent-browser navigate https://app.example.com\nagent-browser wait --load networkidle\nagent-browser profiler stop \"./profiles/build-${BUILD_ID}.json\"\n```\n\n## Output Format\n\nThe output is a JSON file in Chrome Trace Event format:\n\n```json\n{\n  \"traceEvents\": [\n    { \"cat\": \"devtools.timeline\", \"name\": \"RunTask\", \"ph\": \"X\", \"ts\": 12345, \"dur\": 100, ... },\n    ...\n  ],\n  \"metadata\": {\n    \"clock-domain\": \"LINUX_CLOCK_MONOTONIC\"\n  }\n}\n```\n\nThe `metadata.clock-domain` field is set based on the host platform (Linux or macOS). On Windows it is omitted.\n\n## Viewing Profiles\n\nLoad the output JSON file in any of these tools:\n\n- **Chrome DevTools**: Performance panel > Load profile (Ctrl+Shift+I > Performance)\n- **Perfetto UI**: https://ui.perfetto.dev/ -- drag and drop the JSON file\n- **Trace Viewer**: `chrome://tracing` in any Chromium browser\n\n## Limitations\n\n- Only works with Chromium-based browsers (Chrome, Edge). Not supported on Firefox or WebKit.\n- Trace data accumulates in memory while profiling is active (capped at 5 million events). Stop profiling promptly after the area of interest.\n- Data collection on stop has a 30-second timeout. If the browser is unresponsive, the stop command may fail.\n","src/resources/skills/agent-browser/references/proxy-support.md":"# Proxy Support\n\nProxy configuration for geo-testing, rate limiting avoidance, and corporate environments.\n\n**Related**: [commands.md](commands.md) for global options, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Proxy Configuration](#basic-proxy-configuration)\n- [Authenticated Proxy](#authenticated-proxy)\n- [SOCKS Proxy](#socks-proxy)\n- [Proxy Bypass](#proxy-bypass)\n- [Common Use Cases](#common-use-cases)\n- [Verifying Proxy Connection](#verifying-proxy-connection)\n- [Troubleshooting](#troubleshooting)\n- [Best Practices](#best-practices)\n\n## Basic Proxy Configuration\n\nUse the `--proxy` flag or set proxy via environment variable:\n\n```bash\n# Via CLI flag\nagent-browser --proxy \"http://proxy.example.com:8080\" open https://example.com\n\n# Via environment variable\nexport HTTP_PROXY=\"http://proxy.example.com:8080\"\nagent-browser open https://example.com\n\n# HTTPS proxy\nexport HTTPS_PROXY=\"https://proxy.example.com:8080\"\nagent-browser open https://example.com\n\n# Both\nexport HTTP_PROXY=\"http://proxy.example.com:8080\"\nexport HTTPS_PROXY=\"http://proxy.example.com:8080\"\nagent-browser open https://example.com\n```\n\n## Authenticated Proxy\n\nFor proxies requiring authentication:\n\n```bash\n# Include credentials in URL\nexport HTTP_PROXY=\"http://username:password@proxy.example.com:8080\"\nagent-browser open https://example.com\n```\n\n## SOCKS Proxy\n\n```bash\n# SOCKS5 proxy\nexport ALL_PROXY=\"socks5://proxy.example.com:1080\"\nagent-browser open https://example.com\n\n# SOCKS5 with auth\nexport ALL_PROXY=\"socks5://user:pass@proxy.example.com:1080\"\nagent-browser open https://example.com\n```\n\n## Proxy Bypass\n\nSkip proxy for specific domains using `--proxy-bypass` or `NO_PROXY`:\n\n```bash\n# Via CLI flag\nagent-browser --proxy \"http://proxy.example.com:8080\" --proxy-bypass \"localhost,*.internal.com\" open https://example.com\n\n# Via environment variable\nexport NO_PROXY=\"localhost,127.0.0.1,.internal.company.com\"\nagent-browser open https://internal.company.com  # Direct connection\nagent-browser open https://external.com          # Via proxy\n```\n\n## Common Use Cases\n\n### Geo-Location Testing\n\n```bash\n#!/bin/bash\n# Test site from different regions using geo-located proxies\n\nPROXIES=(\n    \"http://us-proxy.example.com:8080\"\n    \"http://eu-proxy.example.com:8080\"\n    \"http://asia-proxy.example.com:8080\"\n)\n\nfor proxy in \"${PROXIES[@]}\"; do\n    export HTTP_PROXY=\"$proxy\"\n    export HTTPS_PROXY=\"$proxy\"\n\n    region=$(echo \"$proxy\" | grep -oP '^\\w+-\\w+')\n    echo \"Testing from: $region\"\n\n    agent-browser --session \"$region\" open https://example.com\n    agent-browser --session \"$region\" screenshot \"./screenshots/$region.png\"\n    agent-browser --session \"$region\" close\ndone\n```\n\n### Rotating Proxies for Scraping\n\n```bash\n#!/bin/bash\n# Rotate through proxy list to avoid rate limiting\n\nPROXY_LIST=(\n    \"http://proxy1.example.com:8080\"\n    \"http://proxy2.example.com:8080\"\n    \"http://proxy3.example.com:8080\"\n)\n\nURLS=(\n    \"https://site.com/page1\"\n    \"https://site.com/page2\"\n    \"https://site.com/page3\"\n)\n\nfor i in \"${!URLS[@]}\"; do\n    proxy_index=$((i % ${#PROXY_LIST[@]}))\n    export HTTP_PROXY=\"${PROXY_LIST[$proxy_index]}\"\n    export HTTPS_PROXY=\"${PROXY_LIST[$proxy_index]}\"\n\n    agent-browser open \"${URLS[$i]}\"\n    agent-browser get text body > \"output-$i.txt\"\n    agent-browser close\n\n    sleep 1  # Polite delay\ndone\n```\n\n### Corporate Network Access\n\n```bash\n#!/bin/bash\n# Access internal sites via corporate proxy\n\nexport HTTP_PROXY=\"http://corpproxy.company.com:8080\"\nexport HTTPS_PROXY=\"http://corpproxy.company.com:8080\"\nexport NO_PROXY=\"localhost,127.0.0.1,.company.com\"\n\n# External sites go through proxy\nagent-browser open https://external-vendor.com\n\n# Internal sites bypass proxy\nagent-browser open https://intranet.company.com\n```\n\n## Verifying Proxy Connection\n\n```bash\n# Check your apparent IP\nagent-browser open https://httpbin.org/ip\nagent-browser get text body\n# Should show proxy's IP, not your real IP\n```\n\n## Troubleshooting\n\n### Proxy Connection Failed\n\n```bash\n# Test proxy connectivity first\ncurl -x http://proxy.example.com:8080 https://httpbin.org/ip\n\n# Check if proxy requires auth\nexport HTTP_PROXY=\"http://user:pass@proxy.example.com:8080\"\n```\n\n### SSL/TLS Errors Through Proxy\n\nSome proxies perform SSL inspection. If you encounter certificate errors:\n\n```bash\n# For testing only - not recommended for production\nagent-browser open https://example.com --ignore-https-errors\n```\n\n### Slow Performance\n\n```bash\n# Use proxy only when necessary\nexport NO_PROXY=\"*.cdn.com,*.static.com\"  # Direct CDN access\n```\n\n## Best Practices\n\n1. **Use environment variables** - Don't hardcode proxy credentials\n2. **Set NO_PROXY appropriately** - Avoid routing local traffic through proxy\n3. **Test proxy before automation** - Verify connectivity with simple requests\n4. **Handle proxy failures gracefully** - Implement retry logic for unstable proxies\n5. **Rotate proxies for large scraping jobs** - Distribute load and avoid bans\n","src/resources/skills/agent-browser/references/session-management.md":"# Session Management\n\nMultiple isolated browser sessions with state persistence and concurrent browsing.\n\n**Related**: [authentication.md](authentication.md) for login patterns, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Named Sessions](#named-sessions)\n- [Session Isolation Properties](#session-isolation-properties)\n- [Session State Persistence](#session-state-persistence)\n- [Common Patterns](#common-patterns)\n- [Default Session](#default-session)\n- [Session Cleanup](#session-cleanup)\n- [Best Practices](#best-practices)\n\n## Named Sessions\n\nUse `--session` flag to isolate browser contexts:\n\n```bash\n# Session 1: Authentication flow\nagent-browser --session auth open https://app.example.com/login\n\n# Session 2: Public browsing (separate cookies, storage)\nagent-browser --session public open https://example.com\n\n# Commands are isolated by session\nagent-browser --session auth fill @e1 \"user@example.com\"\nagent-browser --session public get text body\n```\n\n## Session Isolation Properties\n\nEach session has independent:\n- Cookies\n- LocalStorage / SessionStorage\n- IndexedDB\n- Cache\n- Browsing history\n- Open tabs\n\n## Session State Persistence\n\n### Save Session State\n\n```bash\n# Save cookies, storage, and auth state\nagent-browser state save /path/to/auth-state.json\n```\n\n### Load Session State\n\n```bash\n# Restore saved state\nagent-browser state load /path/to/auth-state.json\n\n# Continue with authenticated session\nagent-browser open https://app.example.com/dashboard\n```\n\n### State File Contents\n\n```json\n{\n  \"cookies\": [...],\n  \"localStorage\": {...},\n  \"sessionStorage\": {...},\n  \"origins\": [...]\n}\n```\n\n## Common Patterns\n\n### Authenticated Session Reuse\n\n```bash\n#!/bin/bash\n# Save login state once, reuse many times\n\nSTATE_FILE=\"/tmp/auth-state.json\"\n\n# Check if we have saved state\nif [[ -f \"$STATE_FILE\" ]]; then\n    agent-browser state load \"$STATE_FILE\"\n    agent-browser open https://app.example.com/dashboard\nelse\n    # Perform login\n    agent-browser open https://app.example.com/login\n    agent-browser snapshot -i\n    agent-browser fill @e1 \"$USERNAME\"\n    agent-browser fill @e2 \"$PASSWORD\"\n    agent-browser click @e3\n    agent-browser wait --load networkidle\n\n    # Save for future use\n    agent-browser state save \"$STATE_FILE\"\nfi\n```\n\n### Concurrent Scraping\n\n```bash\n#!/bin/bash\n# Scrape multiple sites concurrently\n\n# Start all sessions\nagent-browser --session site1 open https://site1.com &\nagent-browser --session site2 open https://site2.com &\nagent-browser --session site3 open https://site3.com &\nwait\n\n# Extract from each\nagent-browser --session site1 get text body > site1.txt\nagent-browser --session site2 get text body > site2.txt\nagent-browser --session site3 get text body > site3.txt\n\n# Cleanup\nagent-browser --session site1 close\nagent-browser --session site2 close\nagent-browser --session site3 close\n```\n\n### A/B Testing Sessions\n\n```bash\n# Test different user experiences\nagent-browser --session variant-a open \"https://app.com?variant=a\"\nagent-browser --session variant-b open \"https://app.com?variant=b\"\n\n# Compare\nagent-browser --session variant-a screenshot /tmp/variant-a.png\nagent-browser --session variant-b screenshot /tmp/variant-b.png\n```\n\n## Default Session\n\nWhen `--session` is omitted, commands use the default session:\n\n```bash\n# These use the same default session\nagent-browser open https://example.com\nagent-browser snapshot -i\nagent-browser close  # Closes default session\n```\n\n## Session Cleanup\n\n```bash\n# Close specific session\nagent-browser --session auth close\n\n# List active sessions\nagent-browser session list\n```\n\n## Best Practices\n\n### 1. Name Sessions Semantically\n\n```bash\n# GOOD: Clear purpose\nagent-browser --session github-auth open https://github.com\nagent-browser --session docs-scrape open https://docs.example.com\n\n# AVOID: Generic names\nagent-browser --session s1 open https://github.com\n```\n\n### 2. Always Clean Up\n\n```bash\n# Close sessions when done\nagent-browser --session auth close\nagent-browser --session scrape close\n```\n\n### 3. Handle State Files Securely\n\n```bash\n# Don't commit state files (contain auth tokens!)\necho \"*.auth-state.json\" >> .gitignore\n\n# Delete after use\nrm /tmp/auth-state.json\n```\n\n### 4. Timeout Long Sessions\n\n```bash\n# Set timeout for automated scripts\ntimeout 60 agent-browser --session long-task get text body\n```\n","src/resources/skills/agent-browser/references/snapshot-refs.md":"# Snapshot and Refs\n\nCompact element references that reduce context usage dramatically for AI agents.\n\n**Related**: [commands.md](commands.md) for full command reference, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [How Refs Work](#how-refs-work)\n- [Snapshot Command](#the-snapshot-command)\n- [Using Refs](#using-refs)\n- [Ref Lifecycle](#ref-lifecycle)\n- [Best Practices](#best-practices)\n- [Ref Notation Details](#ref-notation-details)\n- [Troubleshooting](#troubleshooting)\n\n## How Refs Work\n\nTraditional approach:\n```\nFull DOM/HTML → AI parses → CSS selector → Action (~3000-5000 tokens)\n```\n\nagent-browser approach:\n```\nCompact snapshot → @refs assigned → Direct interaction (~200-400 tokens)\n```\n\n## The Snapshot Command\n\n```bash\n# Basic snapshot (shows page structure)\nagent-browser snapshot\n\n# Interactive snapshot (-i flag) - RECOMMENDED\nagent-browser snapshot -i\n```\n\n### Snapshot Output Format\n\n```\nPage: Example Site - Home\nURL: https://example.com\n\n@e1 [header]\n  @e2 [nav]\n    @e3 [a] \"Home\"\n    @e4 [a] \"Products\"\n    @e5 [a] \"About\"\n  @e6 [button] \"Sign In\"\n\n@e7 [main]\n  @e8 [h1] \"Welcome\"\n  @e9 [form]\n    @e10 [input type=\"email\"] placeholder=\"Email\"\n    @e11 [input type=\"password\"] placeholder=\"Password\"\n    @e12 [button type=\"submit\"] \"Log In\"\n\n@e13 [footer]\n  @e14 [a] \"Privacy Policy\"\n```\n\n## Using Refs\n\nOnce you have refs, interact directly:\n\n```bash\n# Click the \"Sign In\" button\nagent-browser click @e6\n\n# Fill email input\nagent-browser fill @e10 \"user@example.com\"\n\n# Fill password\nagent-browser fill @e11 \"password123\"\n\n# Submit the form\nagent-browser click @e12\n```\n\n## Ref Lifecycle\n\n**IMPORTANT**: Refs are invalidated when the page changes!\n\n```bash\n# Get initial snapshot\nagent-browser snapshot -i\n# @e1 [button] \"Next\"\n\n# Click triggers page change\nagent-browser click @e1\n\n# MUST re-snapshot to get new refs!\nagent-browser snapshot -i\n# @e1 [h1] \"Page 2\"  ← Different element now!\n```\n\n## Best Practices\n\n### 1. Always Snapshot Before Interacting\n\n```bash\n# CORRECT\nagent-browser open https://example.com\nagent-browser snapshot -i          # Get refs first\nagent-browser click @e1            # Use ref\n\n# WRONG\nagent-browser open https://example.com\nagent-browser click @e1            # Ref doesn't exist yet!\n```\n\n### 2. Re-Snapshot After Navigation\n\n```bash\nagent-browser click @e5            # Navigates to new page\nagent-browser snapshot -i          # Get new refs\nagent-browser click @e1            # Use new refs\n```\n\n### 3. Re-Snapshot After Dynamic Changes\n\n```bash\nagent-browser click @e1            # Opens dropdown\nagent-browser snapshot -i          # See dropdown items\nagent-browser click @e7            # Select item\n```\n\n### 4. Snapshot Specific Regions\n\nFor complex pages, snapshot specific areas:\n\n```bash\n# Snapshot just the form\nagent-browser snapshot @e9\n```\n\n## Ref Notation Details\n\n```\n@e1 [tag type=\"value\"] \"text content\" placeholder=\"hint\"\n│    │   │             │               │\n│    │   │             │               └─ Additional attributes\n│    │   │             └─ Visible text\n│    │   └─ Key attributes shown\n│    └─ HTML tag name\n└─ Unique ref ID\n```\n\n### Common Patterns\n\n```\n@e1 [button] \"Submit\"                    # Button with text\n@e2 [input type=\"email\"]                 # Email input\n@e3 [input type=\"password\"]              # Password input\n@e4 [a href=\"/page\"] \"Link Text\"         # Anchor link\n@e5 [select]                             # Dropdown\n@e6 [textarea] placeholder=\"Message\"     # Text area\n@e7 [div class=\"modal\"]                  # Container (when relevant)\n@e8 [img alt=\"Logo\"]                     # Image\n@e9 [checkbox] checked                   # Checked checkbox\n@e10 [radio] selected                    # Selected radio\n```\n\n## Troubleshooting\n\n### \"Ref not found\" Error\n\n```bash\n# Ref may have changed - re-snapshot\nagent-browser snapshot -i\n```\n\n### Element Not Visible in Snapshot\n\n```bash\n# Scroll down to reveal element\nagent-browser scroll down 1000\nagent-browser snapshot -i\n\n# Or wait for dynamic content\nagent-browser wait 1000\nagent-browser snapshot -i\n```\n\n### Too Many Elements\n\n```bash\n# Snapshot specific container\nagent-browser snapshot @e5\n\n# Or use get text for content-only extraction\nagent-browser get text @e5\n```\n","src/resources/skills/agent-browser/references/video-recording.md":"# Video Recording\n\nCapture browser automation as video for debugging, documentation, or verification.\n\n**Related**: [commands.md](commands.md) for full command reference, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Recording](#basic-recording)\n- [Recording Commands](#recording-commands)\n- [Use Cases](#use-cases)\n- [Best Practices](#best-practices)\n- [Output Format](#output-format)\n- [Limitations](#limitations)\n\n## Basic Recording\n\n```bash\n# Start recording\nagent-browser record start ./demo.webm\n\n# Perform actions\nagent-browser open https://example.com\nagent-browser snapshot -i\nagent-browser click @e1\nagent-browser fill @e2 \"test input\"\n\n# Stop and save\nagent-browser record stop\n```\n\n## Recording Commands\n\n```bash\n# Start recording to file\nagent-browser record start ./output.webm\n\n# Stop current recording\nagent-browser record stop\n\n# Restart with new file (stops current + starts new)\nagent-browser record restart ./take2.webm\n```\n\n## Use Cases\n\n### Debugging Failed Automation\n\n```bash\n#!/bin/bash\n# Record automation for debugging\n\nagent-browser record start ./debug-$(date +%Y%m%d-%H%M%S).webm\n\n# Run your automation\nagent-browser open https://app.example.com\nagent-browser snapshot -i\nagent-browser click @e1 || {\n    echo \"Click failed - check recording\"\n    agent-browser record stop\n    exit 1\n}\n\nagent-browser record stop\n```\n\n### Documentation Generation\n\n```bash\n#!/bin/bash\n# Record workflow for documentation\n\nagent-browser record start ./docs/how-to-login.webm\n\nagent-browser open https://app.example.com/login\nagent-browser wait 1000  # Pause for visibility\n\nagent-browser snapshot -i\nagent-browser fill @e1 \"demo@example.com\"\nagent-browser wait 500\n\nagent-browser fill @e2 \"password\"\nagent-browser wait 500\n\nagent-browser click @e3\nagent-browser wait --load networkidle\nagent-browser wait 1000  # Show result\n\nagent-browser record stop\n```\n\n### CI/CD Test Evidence\n\n```bash\n#!/bin/bash\n# Record E2E test runs for CI artifacts\n\nTEST_NAME=\"${1:-e2e-test}\"\nRECORDING_DIR=\"./test-recordings\"\nmkdir -p \"$RECORDING_DIR\"\n\nagent-browser record start \"$RECORDING_DIR/$TEST_NAME-$(date +%s).webm\"\n\n# Run test\nif run_e2e_test; then\n    echo \"Test passed\"\nelse\n    echo \"Test failed - recording saved\"\nfi\n\nagent-browser record stop\n```\n\n## Best Practices\n\n### 1. Add Pauses for Clarity\n\n```bash\n# Slow down for human viewing\nagent-browser click @e1\nagent-browser wait 500  # Let viewer see result\n```\n\n### 2. Use Descriptive Filenames\n\n```bash\n# Include context in filename\nagent-browser record start ./recordings/login-flow-2024-01-15.webm\nagent-browser record start ./recordings/checkout-test-run-42.webm\n```\n\n### 3. Handle Recording in Error Cases\n\n```bash\n#!/bin/bash\nset -e\n\ncleanup() {\n    agent-browser record stop 2>/dev/null || true\n    agent-browser close 2>/dev/null || true\n}\ntrap cleanup EXIT\n\nagent-browser record start ./automation.webm\n# ... automation steps ...\n```\n\n### 4. Combine with Screenshots\n\n```bash\n# Record video AND capture key frames\nagent-browser record start ./flow.webm\n\nagent-browser open https://example.com\nagent-browser screenshot ./screenshots/step1-homepage.png\n\nagent-browser click @e1\nagent-browser screenshot ./screenshots/step2-after-click.png\n\nagent-browser record stop\n```\n\n## Output Format\n\n- Default format: WebM (VP8/VP9 codec)\n- Compatible with all modern browsers and video players\n- Compressed but high quality\n\n## Limitations\n\n- Recording adds slight overhead to automation\n- Large recordings can consume significant disk space\n- Some headless environments may have codec limitations\n","src/resources/skills/api-design/SKILL.md":"---\nname: api-design\ndescription: Design or review an HTTP/REST/GraphQL API for versioning, pagination, error shapes, idempotency, auth, and evolvability. Use when asked to \"design an API\", \"shape the endpoints\", \"design the schema\", \"add a new endpoint\", \"review this API\", or when building/modifying a public or internal HTTP surface. Complements `design-an-interface` (which is interface-agnostic) by covering HTTP-specific concerns like status codes, cache headers, and breaking-change management.\n---\n\n<objective>\nShape an HTTP or GraphQL API so callers get predictable, evolvable, and honest semantics. The deliverable is a concrete endpoint/schema sketch with: URL or operation names, method/verb, request shape, response shape, error shape, auth model, pagination strategy, and versioning stance. Optimize for \"clients that exist in 2 years\" over \"client that's easy to write today\".\n</objective>\n\n<context>\nGSD-2 has `design-an-interface` for general module-interface design; this skill is the HTTP/GraphQL specialization. REST and GraphQL carry baggage — status codes, verbs, nullability, pagination — that a generic interface-design discussion glosses over.\n\nInvocation points:\n- Adding a new public API endpoint\n- Redesigning an internal API boundary between services\n- Code review of a PR that introduces HTTP handlers\n- A slice whose acceptance criteria include \"the API works\"\n- A GraphQL schema change\n</context>\n\n<core_principle>\n**CALLERS OUTLIVE YOUR ASSUMPTIONS.** An API you ship today has to keep working when your internals change, when the mobile app version two is still in use, and when a third party integrates against it. Design for extension, not just for the current caller.\n\n**HONEST STATUS CODES.** 200 OK with `{\"error\": \"not found\"}` is a lie. 404 says not found. Use the HTTP semantics the protocol offers — HTTP clients, caches, and intermediaries rely on them.\n\n**PAGINATION IS NON-OPTIONAL.** Any list endpoint that doesn't paginate will eventually get a request for \"all records\" that kills your database.\n</core_principle>\n\n<process>\n\n## Step 1: Gather the contract\n\nAnswer, or ask (one round, 1–3 questions):\n\n1. **Who are the callers?** Internal service / mobile app / public third-party / same-repo frontend.\n2. **What's the versioning stance?** None / URL-path (`/v1/`) / header-based / GraphQL schema evolution.\n3. **Auth model?** Public / API key / OAuth / session cookie / mTLS / none-but-internal-only.\n4. **Idempotency expectation?** Is a retry safe? Required?\n5. **Consistency model?** Read-your-writes, eventual, serializable?\n\n## Step 2: Resource and operation naming\n\n### REST\n\n- Nouns not verbs in URLs: `POST /users`, not `POST /createUser`.\n- Plural resources: `/users/42`, not `/user/42`.\n- Nested only when the relationship is hierarchical and the child has no independent identity: `/users/42/sessions/3`. Otherwise flat: `/sessions/3?userId=42`.\n- Use subresources for actions that don't fit CRUD: `POST /users/42:deactivate` (colon syntax) or `POST /users/42/actions/deactivate`.\n\n### GraphQL\n\n- Queries are nouns; mutations are verbs: `user(id)`, `createUser(input)`, `deactivateUser(id)`.\n- Group related mutations under an input type: `createUser(input: CreateUserInput!)`.\n- Return the affected object plus any derived/computed fields from mutations — lets clients avoid a refetch.\n\n## Step 3: Methods and status codes\n\n### REST\n\n| Method | Intent | Idempotent? | Default success |\n|---|---|---|---|\n| GET | Read | Yes | 200, or 304 if conditional |\n| POST | Create or non-idempotent action | No | 201 with `Location` on create, 200 on action |\n| PUT | Replace (full-object) | Yes | 200 with body, or 204 |\n| PATCH | Partial update | No (usually) | 200 with body |\n| DELETE | Remove | Yes | 204 |\n\nErrors:\n- 400: caller screwed up the request shape\n- 401: no/invalid auth\n- 403: authed but not allowed\n- 404: resource doesn't exist\n- 409: conflict (version mismatch, unique constraint)\n- 410: gone (vs 404 when the resource previously existed and you want to signal that)\n- 422: validation failed\n- 429: rate-limited — include `Retry-After`\n- 500: genuinely unexpected server error\n- 503: service down or overloaded — include `Retry-After`\n\nNever 200-with-error-body. Never 500 for a 4xx cause.\n\n### GraphQL\n\n- Top-level errors (`errors[]`) for transport-level failures. Domain errors (validation, not-found, forbidden) go in the typed return — use a union or result type.\n- Partial results are expected; design the schema so `null` on a field is meaningful, not a signal of generic failure.\n\n## Step 4: Pagination\n\n- **Cursor-based by default.** Opaque cursor string, `limit`, return `nextCursor` when more exists. Scales, stable under writes.\n- **Offset-based only when:** dataset is small, user needs jump-to-page semantics (admin tables), and you're willing to accept stability drift.\n- **Never \"return everything\"** as default. Put a hard upper bound on `limit` (e.g., 200).\n- GraphQL: use Relay-style connections (`edges`, `pageInfo`) if the ecosystem expects it; otherwise a simpler `{items, nextCursor}` is fine.\n\n## Step 5: Error shape\n\nStandardize one shape and use it everywhere. Example REST:\n\n```json\n{\n  \"error\": {\n    \"code\": \"user_not_found\",\n    \"message\": \"No user with id 42\",\n    \"details\": { \"userId\": 42 },\n    \"requestId\": \"req_abc123\"\n  }\n}\n```\n\n- `code` is machine-readable; stable; documented.\n- `message` is human-readable; can change.\n- `details` carries structured context.\n- `requestId` lets callers report bugs.\n\nErrors don't leak stack traces, file paths, or internal queries.\n\n## Step 6: Idempotency, caching, concurrency\n\n- **Idempotency keys** for POST operations that mustn't double-execute on retry. Caller passes `Idempotency-Key: <uuid>`; server dedupes for a window.\n- **ETags** for GET + conditional updates (`If-Match` on PUT/PATCH).\n- **Cache-Control** on GETs that are safely cacheable.\n- **Optimistic concurrency:** when multiple writers collide, 409 with the current state. Don't silently clobber.\n\n## Step 7: Versioning and evolution\n\n- **Additive changes are free:** new optional fields, new endpoints, new optional query params.\n- **Breaking changes need a plan:** path-versioned (`/v2/`), sunset headers on `/v1/`, deprecation window communicated. Or, for GraphQL, `@deprecated` on fields with a migration note.\n- **Document the contract:** OpenAPI/GraphQL SDL. Keep it in the repo. Make it part of the PR that introduces the change.\n\n## Step 8: Review or write it up\n\nIf this is a review, produce findings in the same shape as `security-review` / `review` — file:line, category, recommendation.\n\nIf this is a new design, produce:\n\n```markdown\n## <API name>\n\n### Scope\n<what the API is for, who calls it>\n\n### Endpoints / Operations\n- `POST /users` — create user. Request: `{email, name}`. Response 201: `{id, email, name, createdAt}` + `Location: /users/<id>`. Errors: 409 email taken, 422 invalid.\n- ...\n\n### Auth\n<model + where to put the credential>\n\n### Pagination\n<cursor shape, max limit>\n\n### Error shape\n<one canonical shape>\n\n### Idempotency / concurrency\n<rules>\n\n### Versioning\n<stance + how breaking changes will be handled>\n\n### OpenAPI / SDL\n<link or inline>\n```\n\nAppend architectural decisions to `.gsd/DECISIONS.md`.\n\n</process>\n\n<anti_patterns>\n\n- **200 OK with `{\"error\": \"...\"}`.** Lies to caches, proxies, retry libraries.\n- **Unbounded list endpoints.** `GET /users` without a `limit` cap will bite you.\n- **Offset pagination at scale.** Drifts under writes; slow at high offsets.\n- **Free-form error messages with no code.** Machine callers can't branch on prose.\n- **Breaking changes in-place.** Callers break; versioning exists for a reason.\n- **Ignoring idempotency on retriable POSTs.** Double-charges, duplicate records.\n- **Auth checks at the handler only, not the service layer.** Defense in depth.\n\n</anti_patterns>\n\n<success_criteria>\n\n- [ ] Every endpoint/operation has named request, response, and error shapes.\n- [ ] Status codes match HTTP semantics — no 200-with-error.\n- [ ] List endpoints paginate; max limit is documented.\n- [ ] A single error shape is used everywhere, with a machine-readable code.\n- [ ] Versioning stance is stated — even if the answer is \"additive only for now.\"\n- [ ] OpenAPI/SDL reflects the design and lives in the repo.\n- [ ] Decisions appear in `.gsd/DECISIONS.md`.\n\n</success_criteria>\n","src/resources/skills/best-practices/SKILL.md":"---\nname: best-practices\ndescription: Apply modern web development best practices for security, compatibility, and code quality. Use when asked to \"apply best practices\", \"security audit\", \"modernize code\", \"code quality review\", or \"check for vulnerabilities\".\nlicense: MIT\nmetadata:\n  author: web-quality-skills\n  version: \"1.0\"\n---\n\n# Best practices\n\nModern web development standards based on Lighthouse best practices audits. Covers security, browser compatibility, and code quality patterns.\n\n## Security\n\n### HTTPS everywhere\n\n**Enforce HTTPS:**\n```html\n<!-- ❌ Mixed content -->\n<img src=\"http://example.com/image.jpg\">\n<script src=\"http://cdn.example.com/script.js\"></script>\n\n<!-- ✅ HTTPS only -->\n<img src=\"https://example.com/image.jpg\">\n<script src=\"https://cdn.example.com/script.js\"></script>\n\n<!-- ✅ Protocol-relative (will use page's protocol) -->\n<img src=\"//example.com/image.jpg\">\n```\n\n**HSTS Header:**\n```\nStrict-Transport-Security: max-age=31536000; includeSubDomains; preload\n```\n\n### Content Security Policy (CSP)\n\n```html\n<!-- Basic CSP via meta tag -->\n<meta http-equiv=\"Content-Security-Policy\" \n      content=\"default-src 'self'; \n               script-src 'self' https://trusted-cdn.com; \n               style-src 'self' 'unsafe-inline';\n               img-src 'self' data: https:;\n               connect-src 'self' https://api.example.com;\">\n\n<!-- Better: HTTP header -->\n```\n\n**CSP Header (recommended):**\n```\nContent-Security-Policy: \n  default-src 'self';\n  script-src 'self' 'nonce-abc123' https://trusted.com;\n  style-src 'self' 'nonce-abc123';\n  img-src 'self' data: https:;\n  connect-src 'self' https://api.example.com;\n  frame-ancestors 'self';\n  base-uri 'self';\n  form-action 'self';\n```\n\n**Using nonces for inline scripts:**\n```html\n<script nonce=\"abc123\">\n  // This inline script is allowed\n</script>\n```\n\n### Security headers\n\n```\n# Prevent clickjacking\nX-Frame-Options: DENY\n\n# Prevent MIME type sniffing\nX-Content-Type-Options: nosniff\n\n# Enable XSS filter (legacy browsers)\nX-XSS-Protection: 1; mode=block\n\n# Control referrer information\nReferrer-Policy: strict-origin-when-cross-origin\n\n# Permissions policy (formerly Feature-Policy)\nPermissions-Policy: geolocation=(), microphone=(), camera=()\n```\n\n### No vulnerable libraries\n\n```bash\n# Check for vulnerabilities\nnpm audit\nyarn audit\n\n# Auto-fix when possible\nnpm audit fix\n\n# Check specific package\nnpm ls lodash\n```\n\n**Keep dependencies updated:**\n```json\n// package.json\n{\n  \"scripts\": {\n    \"audit\": \"npm audit --audit-level=moderate\",\n    \"update\": \"npm update && npm audit fix\"\n  }\n}\n```\n\n**Known vulnerable patterns to avoid:**\n```javascript\n// ❌ Prototype pollution vulnerable patterns\nObject.assign(target, userInput);\n_.merge(target, userInput);\n\n// ✅ Safer alternatives\nconst safeData = JSON.parse(JSON.stringify(userInput));\n```\n\n### Input sanitization\n\n```javascript\n// ❌ XSS vulnerable\nelement.innerHTML = userInput;\ndocument.write(userInput);\n\n// ✅ Safe text content\nelement.textContent = userInput;\n\n// ✅ If HTML needed, sanitize\nimport DOMPurify from 'dompurify';\nelement.innerHTML = DOMPurify.sanitize(userInput);\n```\n\n### Secure cookies\n\n```javascript\n// ❌ Insecure cookie\ndocument.cookie = \"session=abc123\";\n\n// ✅ Secure cookie (server-side)\nSet-Cookie: session=abc123; Secure; HttpOnly; SameSite=Strict; Path=/\n```\n\n---\n\n## Browser compatibility\n\n### Doctype declaration\n\n```html\n<!-- ❌ Missing or invalid doctype -->\n<HTML>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n\n<!-- ✅ HTML5 doctype -->\n<!DOCTYPE html>\n<html lang=\"en\">\n```\n\n### Character encoding\n\n```html\n<!-- ❌ Missing or late charset -->\n<html>\n<head>\n  <title>Page</title>\n  <meta charset=\"UTF-8\">\n</head>\n\n<!-- ✅ Charset as first element in head -->\n<html>\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Page</title>\n</head>\n```\n\n### Viewport meta tag\n\n```html\n<!-- ❌ Missing viewport -->\n<head>\n  <title>Page</title>\n</head>\n\n<!-- ✅ Responsive viewport -->\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <title>Page</title>\n</head>\n```\n\n### Feature detection\n\n```javascript\n// ❌ Browser detection (brittle)\nif (navigator.userAgent.includes('Chrome')) {\n  // Chrome-specific code\n}\n\n// ✅ Feature detection\nif ('IntersectionObserver' in window) {\n  // Use IntersectionObserver\n} else {\n  // Fallback\n}\n\n// ✅ Using @supports in CSS\n@supports (display: grid) {\n  .container {\n    display: grid;\n  }\n}\n\n@supports not (display: grid) {\n  .container {\n    display: flex;\n  }\n}\n```\n\n### Polyfills (when needed)\n\n```html\n<!-- Load polyfills conditionally -->\n<script>\n  if (!('fetch' in window)) {\n    document.write('<script src=\"/polyfills/fetch.js\"><\\/script>');\n  }\n</script>\n\n<!-- Or use polyfill.io -->\n<script src=\"https://polyfill.io/v3/polyfill.min.js?features=fetch,IntersectionObserver\"></script>\n```\n\n---\n\n## Deprecated APIs\n\n### Avoid these\n\n```javascript\n// ❌ document.write (blocks parsing)\ndocument.write('<script src=\"...\"></script>');\n\n// ✅ Dynamic script loading\nconst script = document.createElement('script');\nscript.src = '...';\ndocument.head.appendChild(script);\n\n// ❌ Synchronous XHR (blocks main thread)\nconst xhr = new XMLHttpRequest();\nxhr.open('GET', url, false); // false = synchronous\n\n// ✅ Async fetch\nconst response = await fetch(url);\n\n// ❌ Application Cache (deprecated)\n<html manifest=\"cache.manifest\">\n\n// ✅ Service Workers\nif ('serviceWorker' in navigator) {\n  navigator.serviceWorker.register('/sw.js');\n}\n```\n\n### Event listener passive\n\n```javascript\n// ❌ Non-passive touch/wheel (may block scrolling)\nelement.addEventListener('touchstart', handler);\nelement.addEventListener('wheel', handler);\n\n// ✅ Passive listeners (allows smooth scrolling)\nelement.addEventListener('touchstart', handler, { passive: true });\nelement.addEventListener('wheel', handler, { passive: true });\n\n// ✅ If you need preventDefault, be explicit\nelement.addEventListener('touchstart', handler, { passive: false });\n```\n\n---\n\n## Console & errors\n\n### No console errors\n\n```javascript\n// ❌ Errors in production\nconsole.log('Debug info'); // Remove in production\nthrow new Error('Unhandled'); // Catch all errors\n\n// ✅ Proper error handling\ntry {\n  riskyOperation();\n} catch (error) {\n  // Log to error tracking service\n  errorTracker.captureException(error);\n  // Show user-friendly message\n  showErrorMessage('Something went wrong. Please try again.');\n}\n```\n\n### Error boundaries (React)\n\n```jsx\nclass ErrorBoundary extends React.Component {\n  state = { hasError: false };\n  \n  static getDerivedStateFromError(error) {\n    return { hasError: true };\n  }\n  \n  componentDidCatch(error, info) {\n    errorTracker.captureException(error, { extra: info });\n  }\n  \n  render() {\n    if (this.state.hasError) {\n      return <FallbackUI />;\n    }\n    return this.props.children;\n  }\n}\n\n// Usage\n<ErrorBoundary>\n  <App />\n</ErrorBoundary>\n```\n\n### Global error handler\n\n```javascript\n// Catch unhandled errors\nwindow.addEventListener('error', (event) => {\n  errorTracker.captureException(event.error);\n});\n\n// Catch unhandled promise rejections\nwindow.addEventListener('unhandledrejection', (event) => {\n  errorTracker.captureException(event.reason);\n});\n```\n\n---\n\n## Source maps\n\n### Production configuration\n\n```javascript\n// ❌ Source maps exposed in production\n// webpack.config.js\nmodule.exports = {\n  devtool: 'source-map', // Exposes source code\n};\n\n// ✅ Hidden source maps (uploaded to error tracker)\nmodule.exports = {\n  devtool: 'hidden-source-map',\n};\n\n// ✅ Or no source maps in production\nmodule.exports = {\n  devtool: process.env.NODE_ENV === 'production' ? false : 'source-map',\n};\n```\n\n---\n\n## Performance best practices\n\n### Avoid blocking patterns\n\n```javascript\n// ❌ Blocking script\n<script src=\"heavy-library.js\"></script>\n\n// ✅ Deferred script\n<script defer src=\"heavy-library.js\"></script>\n\n// ❌ Blocking CSS import\n@import url('other-styles.css');\n\n// ✅ Link tags (parallel loading)\n<link rel=\"stylesheet\" href=\"styles.css\">\n<link rel=\"stylesheet\" href=\"other-styles.css\">\n```\n\n### Efficient event handlers\n\n```javascript\n// ❌ Handler on every element\nitems.forEach(item => {\n  item.addEventListener('click', handleClick);\n});\n\n// ✅ Event delegation\ncontainer.addEventListener('click', (e) => {\n  if (e.target.matches('.item')) {\n    handleClick(e);\n  }\n});\n```\n\n### Memory management\n\n```javascript\n// ❌ Memory leak (never removed)\nconst handler = () => { /* ... */ };\nwindow.addEventListener('resize', handler);\n\n// ✅ Cleanup when done\nconst handler = () => { /* ... */ };\nwindow.addEventListener('resize', handler);\n\n// Later, when component unmounts:\nwindow.removeEventListener('resize', handler);\n\n// ✅ Using AbortController\nconst controller = new AbortController();\nwindow.addEventListener('resize', handler, { signal: controller.signal });\n\n// Cleanup:\ncontroller.abort();\n```\n\n---\n\n## Code quality\n\n### Valid HTML\n\n```html\n<!-- ❌ Invalid HTML -->\n<div id=\"header\">\n<div id=\"header\"> <!-- Duplicate ID -->\n\n<ul>\n  <div>Item</div> <!-- Invalid child -->\n</ul>\n\n<a href=\"/\"><button>Click</button></a> <!-- Invalid nesting -->\n\n<!-- ✅ Valid HTML -->\n<header id=\"site-header\">\n</header>\n\n<ul>\n  <li>Item</li>\n</ul>\n\n<a href=\"/\" class=\"button\">Click</a>\n```\n\n### Semantic HTML\n\n```html\n<!-- ❌ Non-semantic -->\n<div class=\"header\">\n  <div class=\"nav\">\n    <div class=\"nav-item\">Home</div>\n  </div>\n</div>\n<div class=\"main\">\n  <div class=\"article\">\n    <div class=\"title\">Headline</div>\n  </div>\n</div>\n\n<!-- ✅ Semantic HTML5 -->\n<header>\n  <nav>\n    <a href=\"/\">Home</a>\n  </nav>\n</header>\n<main>\n  <article>\n    <h1>Headline</h1>\n  </article>\n</main>\n```\n\n### Image aspect ratios\n\n```html\n<!-- ❌ Distorted images -->\n<img src=\"photo.jpg\" width=\"300\" height=\"100\">\n<!-- If actual ratio is 4:3, this squishes the image -->\n\n<!-- ✅ Preserve aspect ratio -->\n<img src=\"photo.jpg\" width=\"300\" height=\"225\">\n<!-- Actual 4:3 dimensions -->\n\n<!-- ✅ CSS object-fit for flexibility -->\n<img src=\"photo.jpg\" style=\"width: 300px; height: 200px; object-fit: cover;\">\n```\n\n---\n\n## Permissions & privacy\n\n### Request permissions properly\n\n```javascript\n// ❌ Request on page load (bad UX, often denied)\nnavigator.geolocation.getCurrentPosition(success, error);\n\n// ✅ Request in context, after user action\nfindNearbyButton.addEventListener('click', async () => {\n  // Explain why you need it\n  if (await showPermissionExplanation()) {\n    navigator.geolocation.getCurrentPosition(success, error);\n  }\n});\n```\n\n### Permissions policy\n\n```html\n<!-- Restrict powerful features -->\n<meta http-equiv=\"Permissions-Policy\" \n      content=\"geolocation=(), camera=(), microphone=()\">\n\n<!-- Or allow for specific origins -->\n<meta http-equiv=\"Permissions-Policy\" \n      content=\"geolocation=(self 'https://maps.example.com')\">\n```\n\n---\n\n## Audit checklist\n\n### Security (critical)\n- [ ] HTTPS enabled, no mixed content\n- [ ] No vulnerable dependencies (`npm audit`)\n- [ ] CSP headers configured\n- [ ] Security headers present\n- [ ] No exposed source maps\n\n### Compatibility\n- [ ] Valid HTML5 doctype\n- [ ] Charset declared first in head\n- [ ] Viewport meta tag present\n- [ ] No deprecated APIs used\n- [ ] Passive event listeners for scroll/touch\n\n### Code quality\n- [ ] No console errors\n- [ ] Valid HTML (no duplicate IDs)\n- [ ] Semantic HTML elements used\n- [ ] Proper error handling\n- [ ] Memory cleanup in components\n\n### UX\n- [ ] No intrusive interstitials\n- [ ] Permission requests in context\n- [ ] Clear error messages\n- [ ] Appropriate image aspect ratios\n\n## Tools\n\n| Tool | Purpose |\n|------|---------|\n| `npm audit` | Dependency vulnerabilities |\n| [SecurityHeaders.com](https://securityheaders.com) | Header analysis |\n| [W3C Validator](https://validator.w3.org) | HTML validation |\n| Lighthouse | Best practices audit |\n| [Observatory](https://observatory.mozilla.org) | Security scan |\n\n## References\n\n- [MDN Web Security](https://developer.mozilla.org/en-US/docs/Web/Security)\n- [OWASP Top 10](https://owasp.org/www-project-top-ten/)\n- [Web Quality Audit](../web-quality-audit/SKILL.md)\n","src/resources/skills/btw/SKILL.md":"---\nname: btw\ndescription: Ask a quick side question about your current work without derailing the main task. Answers from existing conversation context only — no tool calls, no file reads, single concise response. Use when you need a fast answer from what is already in this session.\n---\n\n<objective>\nAnswer a quick side question using only what is already present in the current conversation context. Do not read files, run commands, search, or use any tools. Give a single, concise response and return focus to the main work.\n</objective>\n\n<behavior>\n**This is a side question, not a task.**\n\n- Answer only from information already in the conversation (files read, decisions made, code seen, context established)\n- Do NOT use any tools — no Read, no Bash, no Grep, no Search\n- If the answer requires reading something new, say so briefly and suggest the user ask as a normal prompt instead\n- Keep the response short and direct — one to a few sentences unless the question genuinely needs more\n- Do not summarize the main work, ask follow-up questions, or offer to do anything else\n- After answering, stop — do not prompt for next steps\n</behavior>\n\n<quick_start>\nParse the argument after `/btw` as the question. Answer it directly from context.\n\nIf no argument is provided, ask: \"What did you want to know?\"\n\nIf the question cannot be answered from current context (requires reading a file, running a command, or information not yet in the session), respond with:\n\"I'd need to [read X / run Y / look up Z] to answer that — ask it as a normal prompt when you're ready.\"\n</quick_start>\n\n<examples>\n**Good uses of /btw:**\n- `/btw what was the name of that config file again?` → answers from files already read in session\n- `/btw which branch are we on?` → answers from git context already established\n- `/btw did we already handle the null case in that function?` → answers from code already reviewed\n- `/btw what model does this use?` → answers from code or config already in context\n\n**Not a good fit for /btw (suggest normal prompt):**\n- Questions requiring reading a file not yet seen\n- Questions requiring running a command\n- Questions needing a multi-step answer or follow-up\n- Starting a new task or changing direction\n</examples>\n","src/resources/skills/code-optimizer/SKILL.md":"---\nname: code-optimizer\ndescription: >\n  Deep code optimization audit using parallel specialist agents. Each agent hunts for performance\n  anti-patterns, inefficiencies, and suboptimal code using pattern-based detection (Grep/Glob)\n  WITHOUT reading the full source code first — avoiding anchoring bias on existing implementations.\n  Covers ALL optimization domains: database queries, memory leaks, algorithmic complexity,\n  concurrency, bundle size, dead code, I/O & network, rendering/UI, data structures,\n  error handling, caching, build config, security-performance, logging, and infrastructure.\n  Use when asked to: \"optimize my code\", \"find performance issues\", \"audit code quality\",\n  \"speed up my app\", \"find bottlenecks\", \"code review for performance\", \"find anti-patterns\",\n  \"improve code efficiency\", \"reduce latency\", \"optimize performance\", \"code smell detection\",\n  \"find slow code\", \"optimize this project\", \"performance audit\", \"code optimization\".\n  Also triggers on: \"optimizar codigo\", \"encontrar cuellos de botella\", \"mejorar rendimiento\".\n---\n\n# Code Optimizer\n\nParallel multi-agent code optimization audit. Spawn 13 specialist agents simultaneously, each\nhunting for a different class of performance problem using pattern-based detection.\n\n## Critical Principle: No Code Reading Before Analysis\n\nAgents MUST NOT read source files before searching for patterns. Reading the code first causes\nanchoring bias — the agent accepts the existing implementation as \"reasonable\" and misses\nbetter alternatives. Instead, each agent:\n\n1. Read its assigned reference file from `references/` to load detection patterns\n2. Use Grep/Glob to scan the codebase for anti-patterns\n3. For each finding, ONLY THEN read the surrounding context (5-10 lines) to confirm the issue\n4. Propose the optimal solution based on best practices, NOT based on the existing code\n\n## Workflow\n\n### Step 1: Detect Stack\n\nUse Glob to identify the project's tech stack:\n- `**/package.json` → Node.js/JS/TS (check for React, Next.js, Express, etc.)\n- `**/requirements.txt`, `**/pyproject.toml`, `**/setup.py` → Python\n- `**/go.mod` → Go\n- `**/Cargo.toml` → Rust\n- `**/pom.xml`, `**/build.gradle` → Java\n- `**/Gemfile` → Ruby\n- `**/Dockerfile` → Docker\n- `**/*.sql` → SQL\n- `**/webpack.config.*`, `**/vite.config.*`, `**/tsconfig.json` → Build tools\n\n### Step 2: Spawn 13 Parallel Agents\n\nLaunch ALL agents simultaneously using the Agent tool. Each agent receives:\n- Its domain name and reference file path\n- The detected tech stack (so it can focus on relevant patterns)\n- The project root path\n- Instructions to NOT read code files, only Grep/Glob for patterns\n\n**Agent definitions** (spawn all 13 in a single message):\n\n| # | Agent Name | Reference File | Focus |\n|---|-----------|----------------|-------|\n| 1 | Database & Queries | `references/database-queries.md` | N+1 queries, SELECT *, missing indexes, ORM misuse, connection pooling |\n| 2 | Memory & Resources | `references/memory-resources.md` | Memory leaks, unclosed resources, large allocations, string concat in loops |\n| 3 | Algorithmic Complexity | `references/algorithmic-complexity.md` | O(n^2) patterns, unnecessary iterations, wrong data structures for lookups |\n| 4 | Concurrency & Async | `references/concurrency-async.md` | Sequential awaits, blocking in async, race conditions, unbounded concurrency |\n| 5 | Bundle & Dependencies | `references/bundle-dependencies.md` | Heavy imports, unused deps, duplicate libs, missing lazy loading |\n| 6 | Dead Code & Redundancy | `references/dead-code-redundancy.md` | Unused exports, commented code, dead branches, duplicate logic |\n| 7 | I/O & Network | `references/io-network.md` | Sequential requests, missing batching, no dedup, missing compression |\n| 8 | Rendering & UI | `references/rendering-ui.md` | Re-renders, missing virtualization, layout thrashing, animation perf |\n| 9 | Data Structures | `references/data-structures.md` | Wrong structures, unnecessary copies, inefficient serialization |\n| 10 | Error & Resilience | `references/error-resilience.md` | Missing timeouts, swallowed errors, no retries, no circuit breakers |\n| 11 | Caching & Memoization | `references/caching-memoization.md` | Missing memoization, cache without invalidation, redundant API calls |\n| 12 | Build & Compilation | `references/build-compilation.md` | Dev code in prod, missing optimization flags, slow tests, Docker issues |\n| 13 | Security-Performance | `references/security-performance.md` | Crypto misuse, missing rate limiting, ReDoS, SQL injection vectors |\n\n**Optional agents** (spawn if relevant to detected stack):\n- Logging & Observability (`references/logging-observability.md`) — if logging framework detected\n- Config & Infrastructure (`references/config-infra.md`) — if Docker/deployment config detected\n\n### Agent Prompt Template\n\nEach agent MUST receive this prompt structure:\n\n```\nYou are a {DOMAIN_NAME} optimization specialist. Your job is to find performance\nanti-patterns in the codebase at {PROJECT_ROOT}.\n\nCRITICAL RULES:\n1. DO NOT read source code files before searching. This avoids anchoring bias.\n2. First, read your reference file: {SKILL_DIR}/references/{REFERENCE_FILE}\n3. Use Grep and Glob to search for the patterns described in the reference file.\n4. Only read 5-10 lines of context around each finding to confirm it's a real issue.\n5. Skip patterns that don't match the project's stack: {DETECTED_STACK}\n\nTech stack detected: {DETECTED_STACK}\nProject root: {PROJECT_ROOT}\n\nFor each finding, report:\n- **File**: path:line_number\n- **Pattern**: what anti-pattern was detected\n- **Severity**: CRITICAL / HIGH / MEDIUM / LOW\n- **Current code**: the problematic snippet (keep short)\n- **Why it's slow**: brief explanation of the performance impact\n- **Optimal fix**: the recommended solution (code snippet or approach)\n- **Estimated impact**: qualitative improvement expected (e.g., \"10x faster for large lists\")\n\nIf you find 0 issues in your domain, report \"No issues found\" — this is a valid outcome.\nSort findings by severity (CRITICAL first).\n```\n\n### Step 3: Consolidate Report\n\nAfter all agents complete, consolidate their findings into a single prioritized report:\n\n1. Collect all findings from all agents\n2. Deduplicate (different agents may flag the same code for different reasons)\n3. Sort by severity: CRITICAL > HIGH > MEDIUM > LOW\n4. Group by file (so the user can fix file-by-file)\n5. Present the final report with:\n   - Executive summary: total findings by severity, top 3 most impactful\n   - Detailed findings table grouped by file\n   - Improvement plan: ordered list of fixes from highest to lowest impact\n\n### Report Format\n\n```markdown\n# Code Optimization Audit Report\n\n## Executive Summary\n- **X** critical issues, **Y** high, **Z** medium, **W** low\n- Top 3 highest-impact fixes:\n  1. [brief description] — [estimated impact]\n  2. [brief description] — [estimated impact]\n  3. [brief description] — [estimated impact]\n\n## Findings by File\n\n### `path/to/file.ts`\n\n| # | Severity | Domain | Pattern | Fix | Impact |\n|---|----------|--------|---------|-----|--------|\n| 1 | CRITICAL | Database | N+1 query in loop | Use prefetch_related | 50x fewer queries |\n| 2 | HIGH | Async | Sequential awaits | Use Promise.all | 3x faster |\n\n[... for each file with findings ...]\n\n## Improvement Plan\n\nPriority-ordered steps to implement the fixes:\n\n1. **[CRITICAL] Fix N+1 queries in `api/users.py`**\n   - Current: loop queries user.posts for each user\n   - Fix: add prefetch_related('posts') to queryset\n   - Impact: reduces N+1 to 2 queries\n\n2. **[HIGH] Parallelize API calls in `services/sync.ts`**\n   - Current: 5 sequential await fetch() calls\n   - Fix: Promise.all([fetch1, fetch2, ...])\n   - Impact: ~5x faster sync operation\n\n[... continue for all findings ...]\n```\n","src/resources/skills/code-optimizer/references/algorithmic-complexity.md":"# Algorithmic Complexity\n\n## Grep/Glob Patterns to Detect\n\n### O(n^2) and Worse Patterns\n```\n# Nested loops over same/related collections\nfor.*in.*\\n.*for.*in         (nested for loops)\n\\.forEach\\(.*\\.forEach\\(      (nested forEach)\n\\.map\\(.*\\.map\\(              (nested map)\n\\.filter\\(.*\\.includes\\(      (filter+includes = O(n*m))\n\\.find\\(.*inside.*\\.map\\(     (find inside map)\n\\.indexOf\\(.*inside.*for      (indexOf in loop)\n\\.includes\\(.*inside.*for     (includes in loop)\n# Array as lookup table\narray\\.find\\(.*===            (use Map/Set instead)\narray\\.some\\(.*===            (use Set.has instead)\nlist\\.index\\(                 (Python: use dict instead)\nif.*in\\s+list                 (Python: O(n) lookup in list)\n```\n\n### Unnecessary Iterations\n```\n\\.filter\\(.*\\.length          (filter just to count)\n\\.filter\\(.*\\[0\\]             (filter just to get first - use find)\n\\.map\\(.*\\.filter\\(           (map then filter - combine or reverse order)\n\\.filter\\(.*\\.map\\(.*\\.filter (multiple passes when one suffices)\n\\.sort\\(\\).*\\[0\\]             (sort to get min/max - use Math.min/max or reduce)\n\\.sort\\(\\).*\\.slice\\(0        (sort to get top-k - use partial sort/heap)\nsorted\\(.*\\)\\[0\\]             (Python: use min() instead)\nsorted\\(.*\\)\\[-1\\]            (Python: use max() instead)\n\\.reverse\\(\\).*\\.forEach      (reverse just to iterate backwards)\nObject\\.keys\\(.*\\.map\\(.*Object\\.values  (iterating keys then accessing values)\n```\n\n### Redundant Computation\n```\n# Same computation in loop\nfor.*\\n.*Math\\.              (math operations that could be hoisted)\nfor.*\\n.*\\.length            (accessing .length repeatedly - may be fine, check)\nfor.*\\n.*document\\.querySelector  (DOM queries in loops)\nfor.*\\n.*JSON\\.parse         (parsing same JSON repeatedly)\nfor.*\\n.*new RegExp\\(        (creating regex in loop)\nfor.*\\n.*new Date\\(          (creating Date objects in loop for same date)\n```\n\n### Inefficient Data Structure Choice\n```\n# Using arrays where Set/Map would be better\n\\.push\\(.*\\.includes\\(       (array as unique set)\n\\.filter\\(.*\\.indexOf\\(       (dedup with filter+indexOf)\n\\[\\].*\\.find\\(               (array for lookups)\n# Using objects where Map would be better\n\\{\\}.*\\[.*\\]\\s*=             (frequent dynamic key insertion)\ndelete.*\\[                   (frequent key deletion from object)\n```\n\n## Improvement Strategies\n\n1. **Nested loops**: Pre-build lookup Map/Set, use hash-based approaches\n2. **Filter+includes**: Convert one collection to Set for O(1) lookups\n3. **Sort for min/max**: Use Math.min/max, reduce, or heap for top-k\n4. **Multiple passes**: Combine into single reduce/loop\n5. **Redundant computation**: Hoist invariants out of loops, memoize\n6. **Array as lookup**: Use Map for key-value, Set for existence checks\n7. **String matching in loops**: Pre-compile regex, use Map for exact matches\n","src/resources/skills/code-optimizer/references/build-compilation.md":"# Build & Compilation Optimization\n\n## Grep/Glob Patterns to Detect\n\n### Unoptimized Build Config\n```\n# Webpack\nmode:\\s*['\"]development['\"]        (dev mode in production build)\ndevtool:\\s*['\"]source-map['\"]      (full source maps in production)\ndevtool:\\s*['\"]eval                (eval source maps in production)\n# No code splitting\nsplitChunks.*false                  (code splitting disabled)\n# No minification\nminimize:\\s*false                   (minification disabled)\n# Missing tree shaking\nsideEffects.*true                   (prevents tree shaking)\n```\n\n### Development-Only Code in Production\n```\nconsole\\.log\\(                     (debug logging)\nconsole\\.debug\\(                   (debug logging)\nconsole\\.trace\\(                   (trace logging)\ndebugger;                           (debugger statement)\n\\.only\\(                           (test.only left in)\n\\.skip\\(                           (test.skip left in)\nif\\s*\\(.*process\\.env\\.NODE_ENV.*development  (dev-only code)\n__DEV__                             (React Native dev flag)\n```\n\n### Missing Optimization Flags\n```\n# TypeScript\n\"strict\":\\s*false                  (strict mode disabled)\n\"skipLibCheck\":\\s*false            (slow lib checking)\n\"incremental\":\\s*false             (no incremental compilation)\n# Python\npython\\s+-O                        (check if optimized flag used)\n__debug__                           (debug-only code)\n# Docker\nFROM.*:latest                      (unpinned base image)\nRUN.*pip install(?!.*--no-cache)   (pip without --no-cache-dir)\nRUN.*npm install(?!.*--production) (npm install without --production)\nCOPY\\s+\\.\\s+\\.                     (copying entire context)\n```\n\n### Large/Slow Imports at Startup\n```\n# Top-level heavy imports that could be lazy\nimport.*tensorflow                  (heavy ML library at top)\nimport.*pandas                      (heavy data library at top)\nimport.*matplotlib                  (heavy viz library at top)\nimport.*scipy                       (heavy math library at top)\nfrom.*import\\s+\\*                   (wildcard imports slow startup)\n# Circular imports\nImportError.*circular               (circular import errors)\n```\n\n### Missing Caching in CI/CD\n```\n# No caching steps\nnpm install(?!.*cache)              (npm install without cache)\npip install(?!.*cache)              (pip install without cache)\ngo build(?!.*cache)                 (go build without cache)\ndocker build(?!.*cache)             (docker build without layer cache)\n```\n\n### Slow Test Suite\n```\n# Real I/O in tests\nfetch\\(.*test                       (real network calls in tests)\nrequests\\.\\w+\\(.*test              (real HTTP in Python tests)\nopen\\(.*test                        (real file I/O in tests)\n# No test parallelization\n--runInBand                         (Jest sequential mode)\n-p no:xdist                         (pytest parallelization disabled)\n# Heavy setup/teardown\nbeforeAll.*database                 (real DB setup in tests)\nsetUp.*database                     (real DB in Python tests)\n```\n\n## Improvement Strategies\n\n1. **Build config**: Ensure production mode, minification, tree shaking, code splitting\n2. **Dev code**: Strip console.log/debugger via build plugin (e.g., babel-plugin-transform-remove-console)\n3. **TypeScript**: Enable strict, incremental, skipLibCheck for faster builds\n4. **Docker**: Multi-stage builds, .dockerignore, layer caching, pinned versions\n5. **Lazy imports**: Move heavy imports to function scope where they're needed\n6. **CI caching**: Cache node_modules, pip cache, go build cache, Docker layers\n7. **Test speed**: Mock I/O, run tests in parallel, use in-memory DBs for integration tests\n","src/resources/skills/code-optimizer/references/bundle-dependencies.md":"# Bundle Size & Dependencies\n\n## Grep/Glob Patterns to Detect\n\n### Heavy Imports\n```\nimport\\s+\\w+\\s+from\\s+['\"]lodash['\"]      (full lodash import vs lodash/specific)\nimport\\s+\\w+\\s+from\\s+['\"]moment['\"]      (moment.js - use date-fns/dayjs)\nimport\\s+\\w+\\s+from\\s+['\"]underscore['\"]  (underscore - mostly native now)\nimport\\s+\\*\\s+as                           (wildcard imports prevent tree-shaking)\nrequire\\(['\"]lodash['\"]\\)                   (CJS lodash import)\nfrom\\s+pandas\\s+import\\s+\\*                (full pandas import)\nimport\\s+tensorflow                         (full TF import)\nimport\\s+boto3                              (full AWS SDK)\n```\n\n### Unused Dependencies\n```\n# Check package.json dependencies vs actual imports\n# Check requirements.txt vs actual imports\n# Check go.mod vs actual imports\nimport.*from.*['\"](\\w+)['\"]   (cross-reference with package.json)\n```\n\n### Duplicate Functionality\n```\n# Multiple date libraries\nmoment.*\\n.*date-fns          (both moment and date-fns)\nmoment.*\\n.*dayjs             (both moment and dayjs)\n# Multiple HTTP clients\naxios.*\\n.*node-fetch         (both axios and fetch)\naxios.*\\n.*got                (both axios and got)\n# Multiple utility libraries\nlodash.*\\n.*underscore        (both lodash and underscore)\n# Multiple state managers\nredux.*\\n.*mobx               (both redux and mobx)\nzustand.*\\n.*jotai            (multiple state libs)\n```\n\n### Dev Dependencies in Production\n```\n# devDependencies imported in src/\nimport.*from.*['\"](@testing|jest|mocha|chai|sinon|cypress|storybook)\n# Debug/test code in production\nconsole\\.log\\(\nconsole\\.debug\\(\ndebugger;\n\\.only\\(         (test.only left in)\n```\n\n### Dynamic Imports Missing\n```\n# Large components imported statically that could be lazy\nimport.*Modal       (modals are great candidates for lazy loading)\nimport.*Chart       (charts are heavy)\nimport.*Editor      (rich editors are heavy)\nimport.*PDF         (PDF libs are heavy)\nimport.*Map         (map components are heavy)\n# Route-level components not lazy loaded\nimport.*Page.*from  (page components should often be lazy)\n```\n\n### Large Assets\n```\n# Check for unoptimized assets\n\\.png['\"]          (check if could be webp/avif)\n\\.jpg['\"]          (check if could be webp/avif)\n\\.gif['\"]          (check if could be video/webp)\n\\.svg['\"].*import  (SVGs imported as modules - check size)\nbase64             (inline base64 assets)\ndata:image         (inline images)\n```\n\n## Improvement Strategies\n\n1. **Lodash**: Use `lodash-es/specific` or native equivalents (Array.find, Object.entries, etc.)\n2. **Moment.js**: Replace with date-fns or dayjs (10x smaller)\n3. **Wildcard imports**: Use named imports for tree-shaking\n4. **Unused deps**: Remove from package.json/requirements.txt\n5. **Dynamic imports**: Use React.lazy/import() for heavy, below-fold components\n6. **Images**: Convert to WebP/AVIF, use responsive srcset, lazy load below-fold\n7. **Duplicate libs**: Consolidate to one library per concern\n","src/resources/skills/code-optimizer/references/caching-memoization.md":"# Caching & Memoization\n\n## Grep/Glob Patterns to Detect\n\n### Missing Memoization\n```\n# Expensive computations without caching\ndef\\s+\\w+\\(.*\\).*:\\s*\\n.*for.*for      (Python: expensive function without @lru_cache)\nfunction\\s+\\w+\\(.*\\).*\\{.*for.*for     (JS: expensive function without memoization)\n# React missing useMemo/useCallback\nconst\\s+\\w+\\s*=\\s*\\w+\\.filter\\(        (derived data on every render)\nconst\\s+\\w+\\s*=\\s*\\w+\\.map\\(           (derived data on every render)\nconst\\s+\\w+\\s*=\\s*\\w+\\.reduce\\(        (derived data on every render)\nconst\\s+\\w+\\s*=\\s*\\w+\\.sort\\(          (sorting on every render)\n# Same computation called multiple times\n(\\w+)\\(same_args\\).*\\1\\(same_args\\)    (same function, same args, called twice)\n```\n\n### Cache Without Invalidation\n```\ncache\\s*=\\s*\\{\\}                        (cache without TTL or max size)\n_cache\\s*=\\s*\\{\\}                       (module cache without eviction)\nmemo\\s*=\\s*\\{\\}                         (memo without invalidation)\n\\.cache\\s*=\\s*\\{\\}                      (instance cache without cleanup)\nCACHE_TTL.*=.*(?:86400|3600.*24)       (very long TTL - stale data risk)\n```\n\n### Redundant API/DB Calls\n```\n# Same query executed multiple times\n\\.query\\(.*same.*\\.query\\(             (duplicate queries)\nfetch\\(['\"]same_url['\"]\\).*fetch\\(     (duplicate fetches)\n# No SWR/stale-while-revalidate\nuseEffect\\(.*fetch\\(.*\\[\\]            (fetch on every mount without caching)\nuseEffect\\(.*axios\\.\\w+\\(.*\\[\\]       (API call on every mount)\ncomponentDidMount.*fetch               (fetch without caching layer)\n```\n\n### Over-Caching\n```\n# Caching things that change frequently\ncache.*user.*session                   (caching session-specific data)\ncache.*real.?time                      (caching real-time data)\ncache.*current.*time                   (caching time-dependent data)\n# Caching large objects\ncache\\[.*\\]\\s*=\\s*.*large             (large objects in cache)\n```\n\n### Missing HTTP Caching\n```\n# API responses without cache headers\nres\\.json\\(                            (check if Cache-Control is set)\nreturn\\s+Response\\(                    (check if cache headers are set)\nreturn\\s+JsonResponse\\(               (Django: check cache headers)\n# Static assets without long cache\nexpress\\.static\\(                      (check maxAge setting)\nnginx.*location.*static               (check expires/cache-control)\n```\n\n### Computed Properties Recalculated\n```\n# Getters that compute on every access\nget\\s+\\w+\\(\\)\\s*\\{.*return.*\\.filter   (getter computing on each access)\nget\\s+\\w+\\(\\)\\s*\\{.*return.*\\.map      (getter computing on each access)\n@property\\s*\\n\\s*def.*\\n.*for          (Python property computing in loop)\n```\n\n## Improvement Strategies\n\n1. **Memoization**: Use @lru_cache (Python), useMemo/useCallback (React), _.memoize (JS)\n2. **Cache invalidation**: Always set TTL and max size; prefer LRU eviction\n3. **API caching**: Use SWR/React Query for client, Redis/Memcached for server\n4. **HTTP caching**: Set Cache-Control headers, use ETags, stale-while-revalidate\n5. **Computed properties**: Cache results with dirty flag or use memoized selectors (reselect)\n6. **Request deduplication**: Deduplicate identical in-flight requests\n7. **Multi-level cache**: L1 (in-memory) -> L2 (Redis) -> L3 (DB) for read-heavy workloads\n","src/resources/skills/code-optimizer/references/concurrency-async.md":"# Concurrency & Async Patterns\n\n## Grep/Glob Patterns to Detect\n\n### Sequential Async (Should Be Parallel)\n```\nawait.*\\n.*await.*\\n.*await    (multiple sequential awaits that could be parallel)\nfor.*await                      (sequential await in loop)\n\\.then\\(.*\\.then\\(.*\\.then\\(   (promise chain that could be Promise.all)\n# Python\nawait.*\\n.*await.*\\n.*await    (sequential awaits)\nfor.*in.*:\\n.*await            (await in loop)\n```\n\n### Missing Parallelization\n```\n# Should use Promise.all / asyncio.gather\nfetch\\(.*\\n.*fetch\\(           (sequential fetches)\naxios\\.\\w+\\(.*\\n.*axios\\.     (sequential HTTP calls)\nrequests\\.\\w+\\(.*\\n.*requests\\. (Python sequential requests)\n```\n\n### Blocking Operations in Async Context\n```\n# Node.js sync operations in async code\nfs\\.readFileSync               (blocking file read)\nfs\\.writeFileSync              (blocking file write)\nfs\\.existsSync                 (blocking existence check)\nchild_process\\.execSync        (blocking exec)\n\\.readFileSync\\(               (any sync file operation)\n# Python blocking in async\ntime\\.sleep\\(                  (use asyncio.sleep instead)\nrequests\\.                     (use aiohttp/httpx instead)\nopen\\(.*\\.read\\(\\)            (use aiofiles instead)\nos\\.path\\.exists               (use aio equivalent)\n```\n\n### Race Conditions & Thread Safety\n```\n# Shared mutable state\nglobal\\s+\\w+.*=               (Python global mutation)\nthreading\\.Thread.*shared      (shared state across threads)\n# Missing locks\n\\.append\\(.*thread             (list append without lock)\n\\+=.*without.*lock             (increment without lock)\n# JavaScript\nlet\\s+\\w+.*=.*\\n.*async       (mutable let used in async)\n```\n\n### Unbounded Concurrency\n```\n# No concurrency limit\n\\.map\\(.*fetch                 (unbounded parallel fetches)\n\\.map\\(.*axios                 (unbounded parallel requests)\nPromise\\.all\\(.*\\.map\\(        (all items in parallel, no limit)\nasyncio\\.gather\\(.*for         (all coroutines at once)\n# Missing backpressure\nwhile.*true.*await             (infinite async loop without backpressure)\n```\n\n### Error Handling in Async\n```\n# Unhandled rejections\n\\.then\\(.*without.*\\.catch     (promise without catch)\nasync.*without.*try.*catch     (async without error handling)\n# Swallowed errors\ncatch\\s*\\(\\s*\\)\\s*\\{          (empty catch block)\nexcept:\\s*$                    (bare except)\nexcept\\s+Exception\\s*:.*pass  (catch-all with pass)\n```\n\n## Improvement Strategies\n\n1. **Sequential awaits**: Use Promise.all/allSettled, asyncio.gather for independent operations\n2. **Await in loops**: Batch with Promise.all or use p-limit for controlled concurrency\n3. **Blocking in async**: Replace sync APIs with async equivalents\n4. **Race conditions**: Use locks, atomic operations, or immutable patterns\n5. **Unbounded concurrency**: Use semaphores, p-limit, connection pools\n6. **Error handling**: Always catch async errors, use Promise.allSettled for partial failure tolerance\n7. **Backpressure**: Use queues, streaming, or batching for producer-consumer patterns\n","src/resources/skills/code-optimizer/references/config-infra.md":"# Configuration & Infrastructure Inefficiencies\n\n## Grep/Glob Patterns to Detect\n\n### Missing Connection Pooling\n```\n# New connection per request\ncreate_engine\\(.*(?!.*pool)        (SQLAlchemy without pool config)\nnew Pool\\(.*(?!.*max)              (pg Pool without max connections)\nmongoose\\.connect\\(.*(?!.*pool)    (Mongoose without pool)\nDriverManager\\.getConnection\\(     (Java: new connection per call)\npsycopg2\\.connect\\(.*(?!.*pool)   (psycopg2 without pool)\nredis\\.createClient\\(.*per.*request (new Redis client per request)\n```\n\n### Missing Environment-Based Config\n```\nhardcoded.*url                     (hardcoded URLs)\n['\"]http://localhost               (hardcoded localhost URLs)\n['\"]127\\.0\\.0\\.1                   (hardcoded localhost IPs)\npassword\\s*=\\s*['\"]                (hardcoded passwords)\napi.?key\\s*=\\s*['\"]               (hardcoded API keys)\nsecret\\s*=\\s*['\"]                  (hardcoded secrets)\nport\\s*=\\s*\\d{4}                   (hardcoded port numbers)\n```\n\n### Missing Process Management\n```\n# Single-threaded Node.js without clustering\napp\\.listen\\(.*(?!.*cluster)       (Node without cluster module)\n# Python without proper WSGI/ASGI workers\n\\.run\\(.*debug=True                (Flask debug mode)\nuvicorn\\.run\\(.*workers=1          (single worker)\ngunicorn.*-w\\s*1\\b                 (single gunicorn worker)\n```\n\n### Docker/Container Issues\n```\nFROM.*:latest                      (unpinned image version)\nRUN.*apt-get.*&&.*apt-get         (check if apt cache is cleaned)\nCOPY\\s+\\.\\s+\\.                     (copying entire context - no .dockerignore)\nRUN.*npm install\\b(?!.*--production) (installing devDeps in production)\nRUN.*pip install\\b(?!.*--no-cache) (pip without cache clearing)\n# Multiple RUN commands that should be combined\nRUN.*\\nRUN.*\\nRUN                  (multiple RUN layers)\n```\n\n### Missing Health Checks\n```\n# Services without health endpoints\napp\\.(listen|start)\\(.*(?!.*health) (server without health check)\n# Docker without HEALTHCHECK\nDockerfile.*(?!.*HEALTHCHECK)       (Dockerfile without health check)\n```\n\n### Inefficient Polling\n```\nsetInterval\\(.*fetch               (polling instead of WebSocket/SSE)\nsetInterval\\(.*axios               (polling instead of push)\nwhile.*sleep.*fetch                 (polling loop)\ntime\\.sleep\\(.*requests            (Python: polling with sleep)\n```\n\n## Improvement Strategies\n\n1. **Connection pooling**: Configure pool_size, max_overflow, pool_recycle\n2. **Environment config**: Use .env files, config libraries, never hardcode secrets\n3. **Process management**: Use cluster mode (Node), multiple workers (Python ASGI/WSGI)\n4. **Docker**: Multi-stage builds, .dockerignore, combine RUN layers, pin versions\n5. **Health checks**: Add /health endpoint, Docker HEALTHCHECK, readiness/liveness probes\n6. **Polling -> Push**: Use WebSocket, SSE, or long-polling instead of interval polling\n","src/resources/skills/code-optimizer/references/data-structures.md":"# Data Structures & Serialization\n\n## Grep/Glob Patterns to Detect\n\n### Wrong Data Structure for the Job\n```\n# Array used for frequent lookups (should be Map/Set/dict)\n\\.find\\(.*===                  (linear search - use Map)\n\\.findIndex\\(.*===             (linear search for index)\n\\.includes\\(.*inside.*loop     (O(n) lookup in loop)\n\\.indexOf\\(.*inside.*loop      (O(n) lookup in loop)\nif.*in\\s+\\[                    (Python: list membership test)\nlist\\.count\\(                  (Python: counting in list)\n\n# Searching sorted data linearly (should use binary search)\n\\.find\\(.*sorted               (linear search on sorted array)\nfor.*sorted                    (iterating sorted data to find)\n\n# Using objects where Map is better (non-string keys, frequent add/delete)\n\\w+\\[\\w+\\.id\\]\\s*=             (object with dynamic keys from IDs)\ndelete\\s+\\w+\\[                 (frequent deletion from object)\nObject\\.keys\\(.*\\.length       (counting object keys - Map.size is O(1))\n\n# Using array for queue/deque operations\n\\.shift\\(\\)                    (Array.shift is O(n) - use proper queue)\n\\.unshift\\(                    (Array.unshift is O(n))\n```\n\n### Unnecessary Deep Copies\n```\nJSON\\.parse\\(JSON\\.stringify    (JSON round-trip for deep clone)\n\\.map\\(.*\\.map\\(.*spread       (nested spread for deep copy)\n\\{\\.\\.\\..*\\{\\.\\.\\.             (nested object spread)\nstructuredClone\\(.*inside.*loop (deep cloning in loop)\ncopy\\.deepcopy\\(.*loop         (Python deepcopy in loop)\nimport\\s+copy                  (check if deepcopy is overused)\n```\n\n### Inefficient Serialization\n```\n# JSON for internal communication (use binary formats)\nJSON\\.stringify.*JSON\\.parse.*internal\npickle\\.dump.*pickle\\.load     (Python: consider msgpack for cross-language)\n# Serializing more than needed\nJSON\\.stringify\\(.*entire      (serializing entire object when subset needed)\n\\.toJSON\\(\\)                   (check what's being serialized)\n# Repeated serialization\nJSON\\.stringify\\(.*loop        (stringifying in loop)\nJSON\\.parse\\(.*loop            (parsing in loop)\n```\n\n### Unnecessary Object Creation\n```\nnew Date\\(.*inside.*loop       (creating Date objects in loop)\nnew RegExp\\(.*inside.*loop     (compiling regex in loop)\nnew URL\\(.*inside.*loop        (creating URL objects in loop)\n\\.split\\(.*\\.join\\(            (split then join - use replace)\n\\.toString\\(\\).*\\.split\\(      (unnecessary string conversion)\nArray\\.from\\(.*Array\\.from\\(   (double Array.from)\n```\n\n### Immutability Overhead\n```\n# Excessive spread operators\n\\{\\.\\.\\.state,                 (spreading large state objects)\n\\[\\.\\.\\.array,                 (spreading large arrays)\n\\.map\\(.*=>.*\\{\\.\\.\\.         (creating new objects in map with spread)\n# Immer not used where it should be\nproduce\\(                      (check if immer is used consistently)\n```\n\n## Improvement Strategies\n\n1. **Array -> Map/Set**: Use Map for key-value lookups, Set for membership testing\n2. **Array.shift/unshift**: Use a proper deque/queue implementation\n3. **Deep copies**: Use structuredClone (modern), or targeted shallow copies\n4. **Serialization**: Use msgpack/protobuf for internal services, only JSON for external APIs\n5. **Object creation in loops**: Hoist object creation, reuse instances, use object pools\n6. **Large state spreads**: Use Immer's produce(), or targeted updates\n7. **Binary search**: Use on sorted data instead of linear search\n","src/resources/skills/code-optimizer/references/database-queries.md":"# Database & Query Optimization\n\n## Grep/Glob Patterns to Detect\n\n### N+1 Query Problems\n```\n# ORM loops - querying inside iterations\nfor.*in.*\\.all\\(\\)\nfor.*in.*\\.filter\\(\nfor.*in.*\\.objects\\.\n\\.prefetch_related  (absence of - check if loops exist WITHOUT prefetch)\n\\.select_related    (absence of - check if FK access exists WITHOUT select_related)\n# SQLAlchemy\nsession\\.query.*for.*in\n\\.lazy\\s*=\\s*True\n# ActiveRecord\n\\.each.*\\.where\n\\.map.*\\.find\n# Sequelize / TypeORM\nfindOne.*inside.*map\nfindOne.*inside.*for\nawait.*find.*inside.*loop\n```\n\n### Unoptimized Queries\n```\nSELECT \\*\nSELECT.*FROM.*WITHOUT.*WHERE  (full table scans)\nLIKE '%           (leading wildcard - can't use index)\nORDER BY.*RAND()\nNOT IN.*SELECT     (subquery instead of JOIN)\nDISTINCT.*SELECT \\*\nGROUP BY.*without.*index\n\\.raw\\(.*SELECT    (raw queries - potential SQL injection too)\nCOUNT\\(\\*\\).*WHERE  (count with filter vs indexed count)\n```\n\n### Missing Indexes (Heuristic)\n```\nWHERE.*=.*AND.*=    (composite queries without composite index)\nORDER BY.*multiple columns\nJOIN.*ON.*without index hint\n\\.filter\\(.*__in=   (IN queries on large sets)\n```\n\n### ORM Anti-patterns\n```\n\\.save\\(\\).*inside.*loop    (batch update instead)\n\\.create\\(\\).*inside.*loop  (bulk_create instead)\n\\.update\\(\\).*for.*in       (queryset.update instead)\nlen\\(.*\\.all\\(\\)\\)          (.count() instead)\nlist\\(.*\\.all\\(\\)\\)         (unnecessary materialization)\nif.*\\.exists\\(\\).*\\.first\\(\\)  (double query)\n\\.values\\(\\).*\\.values\\(\\)     (chained values)\n```\n\n### Connection Management\n```\n# Missing connection pooling\ncreate_engine\\(.*pool_size  (check if pool is configured)\nnew Pool\\(                   (check pool settings)\nmax_connections             (check if reasonable)\n# Unclosed connections\nconnection\\.open.*without.*close\ncursor.*without.*close\n```\n\n## Improvement Strategies\n\n1. **N+1 Queries**: Use eager loading (prefetch_related, select_related, JOIN FETCH, include/eager)\n2. **SELECT ***: Select only needed columns\n3. **Missing indexes**: Add indexes on frequently filtered/joined columns\n4. **Loop queries**: Use bulk operations (bulk_create, bulk_update, executemany)\n5. **Connection pooling**: Configure connection pools with appropriate size\n6. **Query caching**: Cache frequently-read, rarely-changing data\n7. **Pagination**: Never load unbounded result sets\n","src/resources/skills/code-optimizer/references/dead-code-redundancy.md":"# Dead Code & Redundancy\n\n## Grep/Glob Patterns to Detect\n\n### Unused Exports/Functions\n```\nexport\\s+(function|const|class)\\s+\\w+    (cross-reference: is it imported anywhere?)\ndef\\s+\\w+\\(                              (cross-reference: is it called anywhere?)\npublic\\s+(static\\s+)?\\w+\\s+\\w+\\(        (Java/C# methods - are they called?)\nfunc\\s+\\w+\\(                             (Go functions - are they called?)\n```\n\n### Unused Imports\n```\nimport.*from.*['\"].*['\"]    (cross-reference with usage in file)\nfrom\\s+\\w+\\s+import\\s+\\w+  (Python: check if imported name is used)\nrequire\\(['\"].*['\"]\\)       (CJS: check if result is used)\nuse\\s+\\w+;                  (Rust: check if used)\n```\n\n### Commented-Out Code\n```\n//\\s*(function|const|let|var|class|import|return|if|for|while)\n#\\s*(def|class|import|return|if|for|while)\n/\\*[\\s\\S]*?(function|class|import)[\\s\\S]*?\\*/\n```\n\n### Dead Branches\n```\nif\\s*\\(\\s*false\\s*\\)        (always-false condition)\nif\\s*\\(\\s*true\\s*\\)         (always-true condition - dead else)\nif\\s*\\(\\s*0\\s*\\)            (falsy constant)\nif\\s*\\(\\s*['\"]['\"]          (empty string - always falsy)\nTODO.*remove                 (TODOs indicating dead code)\nFIXME.*remove\nHACK.*temporary\n# Feature flags stuck off\nFEATURE_.*=\\s*false\nENABLE_.*=\\s*false\n```\n\n### Duplicate Logic\n```\n# Similar function signatures in same file or nearby files\nfunction\\s+\\w*(get|fetch|load|process|handle)\\w*\\(   (many similar handlers)\ndef\\s+\\w*(get|fetch|load|process|handle)\\w*\\(        (Python: similar functions)\n# Copy-paste indicators\n# Same code block appearing multiple times (use Grep to find identical blocks)\n```\n\n### Deprecated/Legacy Code\n```\n@deprecated\n@Deprecated\n# deprecated\n\\.deprecated\nDEPRECATED\nlegacy\nLegacy\nLEGACY\n__legacy__\n_old\\b\n_backup\\b\n_v[0-9]\\b       (versioned functions like process_v1)\n```\n\n### Unreachable Code\n```\nreturn.*\\n\\s*(var|let|const|function)   (code after return)\nthrow.*\\n\\s*(var|let|const|function)    (code after throw)\nexit\\(\\).*\\n                            (code after exit)\nsys\\.exit\\(.*\\n                         (Python: code after sys.exit)\nbreak\\s*;\\s*\\n\\s*\\w                     (code after break)\n```\n\n## Improvement Strategies\n\n1. **Unused exports**: Remove and verify no external consumers (check all import statements)\n2. **Unused imports**: Remove with IDE or linting tooling\n3. **Commented code**: Delete it - version control preserves history\n4. **Dead branches**: Remove unreachable code, clean up feature flags\n5. **Duplicate logic**: Extract shared function, use strategy pattern if variants differ slightly\n6. **Deprecated code**: Plan migration, remove after all callers are updated\n7. **Unreachable code**: Remove statements after return/throw/exit\n","src/resources/skills/code-optimizer/references/error-resilience.md":"# Error Handling & Resilience\n\n## Grep/Glob Patterns to Detect\n\n### Missing Timeouts\n```\nfetch\\(.*(?!.*timeout)         (fetch without timeout)\naxios\\.\\w+\\(.*(?!.*timeout)   (axios without timeout)\nrequests\\.\\w+\\(.*(?!.*timeout) (Python requests without timeout)\nhttp\\.\\w+\\(.*(?!.*timeout)    (http call without timeout)\nnew Promise\\(.*(?!.*setTimeout) (promise without timeout)\n\\.connect\\(.*(?!.*timeout)     (DB/socket connect without timeout)\n```\n\n### Swallowed Errors\n```\ncatch\\s*\\(\\s*\\w*\\s*\\)\\s*\\{\\s*\\}  (empty catch block)\ncatch\\s*\\(\\s*\\)\\s*\\{\\s*\\}        (empty catch, no error param)\nexcept:\\s*$                        (bare except)\nexcept\\s+Exception.*pass          (catch-all with pass)\nexcept\\s+Exception.*continue      (catch-all with continue)\n\\.catch\\(\\s*\\(\\)\\s*=>\\s*\\{\\s*\\}\\) (empty .catch handler)\n\\.catch\\(\\s*\\(\\)\\s*=>\\s*null\\)    (swallowing with null)\non_error.*pass                     (error handler that does nothing)\n```\n\n### Missing Retries for Transient Failures\n```\n# Network calls without retry logic\nfetch\\(.*(?!.*retry)           (fetch without retry)\naxios\\.\\w+\\(.*(?!.*retry)     (API call without retry)\nrequests\\.\\w+\\(.*(?!.*retry)  (Python request without retry)\n# Database operations without retry\n\\.query\\(.*(?!.*retry)         (DB query without retry)\n\\.execute\\(.*(?!.*retry)       (DB execute without retry)\n```\n\n### No Circuit Breaker\n```\n# Repeated calls to potentially failing services without circuit breaking\nwhile.*retry.*fetch            (retry loop without circuit break)\nMAX_RETRIES.*=.*[5-9]|[1-9]\\d+ (high retry count without circuit breaker)\n```\n\n### Resource Cleanup on Error\n```\n# try without finally for resource cleanup\ntry\\s*\\{.*open.*(?!.*finally)   (open resource without finally)\ntry:.*open\\(.*(?!.*finally)     (Python: open without finally or context manager)\n# Async cleanup missing\nasync.*try.*(?!.*finally)       (async operation without cleanup)\n```\n\n### Cascading Failures\n```\n# No fallback/default values\n\\?\\?.*undefined                 (check fallback quality)\n\\|\\|.*null                      (check fallback quality)\n\\.get\\(.*,\\s*None\\)            (Python: check if None is appropriate default)\n# No graceful degradation\ncatch.*throw                    (catching just to re-throw - no degradation)\ncatch.*return\\s+null            (returning null on error - caller may not handle)\n```\n\n### Logging Without Action\n```\nconsole\\.error\\(.*(?!.*throw|return|retry)  (logging error but not handling it)\nlogger\\.error\\(.*(?!.*raise|return|retry)   (Python: logging without action)\nprint\\(.*error.*(?!.*raise|return)          (print error without handling)\n```\n\n## Improvement Strategies\n\n1. **Timeouts**: Add timeouts to ALL external calls (network, DB, file I/O). Use AbortController for fetch\n2. **Swallowed errors**: At minimum log errors, prefer explicit handling or re-throwing\n3. **Retries**: Implement exponential backoff with jitter for transient failures\n4. **Circuit breakers**: Use circuit breaker pattern for external service calls\n5. **Resource cleanup**: Use try-finally, context managers, or using statements\n6. **Graceful degradation**: Return cached/default data instead of failing completely\n7. **Error propagation**: Don't catch errors you can't handle - let them bubble up\n","src/resources/skills/code-optimizer/references/io-network.md":"# I/O & Network Optimization\n\n## Grep/Glob Patterns to Detect\n\n### Sequential Requests (Should Be Batched/Parallel)\n```\nfetch\\(.*\\n.*fetch\\(           (sequential fetch calls)\naxios\\.\\w+\\(.*\\n.*axios\\.     (sequential axios calls)\nrequests\\.\\w+\\(.*\\n.*requests (sequential Python requests)\nhttp\\.\\w+\\(.*\\n.*http\\.       (sequential Node http calls)\n\\.get\\(.*\\n.*\\.get\\(           (sequential GET requests)\n\\.post\\(.*\\n.*\\.post\\(         (sequential POST requests)\n```\n\n### Missing Batching\n```\n# Individual API calls in loops\nfor.*\\n.*fetch\\(               (fetch in loop)\nfor.*\\n.*axios\\.               (axios in loop)\nfor.*\\n.*requests\\.            (requests in loop)\n\\.map\\(.*fetch                 (map with individual fetches)\n\\.forEach\\(.*fetch             (forEach with individual fetches)\n# Individual DB writes in loops\n\\.save\\(\\).*for                (save in loop - should batch)\n\\.insert\\(.*for                (insert in loop - should bulk insert)\n```\n\n### No Request Deduplication\n```\n# Same endpoint called multiple times\nfetch\\(['\"]([^'\"]+)['\"]\\)      (check for duplicate URLs)\naxios\\.\\w+\\(['\"]([^'\"]+)['\"]  (check for duplicate URLs)\nuseQuery\\(.*['\"]([^'\"]+)['\"]  (check for duplicate query keys)\n```\n\n### Missing Compression\n```\n# Large payload without compression\nContent-Type.*application/json  (check if gzip/br enabled)\nres\\.json\\(                     (response without compression middleware)\n# No compression middleware\nexpress\\(\\).*without.*compression\n```\n\n### Inefficient Serialization\n```\nJSON\\.stringify\\(.*large        (stringifying large objects)\nJSON\\.parse\\(.*JSON\\.stringify  (deep clone via JSON - use structuredClone)\npickle\\.dumps\\(                 (Python: consider msgpack/protobuf for performance)\nyaml\\.dump\\(.*yaml\\.load\\(     (YAML round-trip - slow for data exchange)\n```\n\n### Missing Streaming\n```\n\\.readFile\\(                   (read entire file vs createReadStream)\n\\.readFileSync\\(               (sync + entire file)\nbody\\.json\\(\\)                 (parse entire body vs streaming parser)\n\\.text\\(\\)                     (entire response as text)\n\\.json\\(\\).*large              (entire JSON response in memory)\nresponse\\.data                 (entire response buffered)\n```\n\n### Missing Caching Headers\n```\n# API responses without caching\nres\\.json\\(.*without.*cache-control\nres\\.send\\(.*without.*etag\n# Static assets without cache headers\nexpress\\.static\\(.*without.*maxAge\n```\n\n### Retry Without Backoff\n```\nretry.*count                   (check if exponential backoff exists)\nwhile.*retry                   (retry loop without delay increase)\ncatch.*retry                   (catch-retry without backoff)\nMAX_RETRIES                    (check backoff strategy)\n```\n\n## Improvement Strategies\n\n1. **Sequential requests**: Use Promise.all, asyncio.gather, or batch APIs\n2. **Loop requests**: Batch into single API call or use DataLoader pattern\n3. **Deduplication**: Use request deduplication (SWR, React Query, custom cache)\n4. **Compression**: Enable gzip/brotli at server and CDN level\n5. **Serialization**: Use efficient formats (protobuf, msgpack) for internal services\n6. **Streaming**: Use streams for large files/responses, NDJSON for large JSON\n7. **Caching**: Set appropriate Cache-Control, ETag, use stale-while-revalidate\n8. **Retries**: Implement exponential backoff with jitter\n","src/resources/skills/code-optimizer/references/logging-observability.md":"# Logging & Observability Performance\n\n## Grep/Glob Patterns to Detect\n\n### Excessive Logging\n```\nconsole\\.log\\(                     (console.log in production code)\nconsole\\.debug\\(                   (console.debug in production)\nprint\\(.*debug                     (Python print debugging)\nlogger\\.debug\\(.*inside.*loop      (debug logging in hot loop)\nlog\\.\\w+\\(.*inside.*for            (any logging in tight loop)\nconsole\\.log\\(JSON\\.stringify\\(    (serializing objects just to log)\n```\n\n### Expensive String Formatting in Logs\n```\n# String interpolation/formatting when log level is disabled\nlogger\\.debug\\(f\"                  (Python f-string even when debug disabled)\nlogger\\.debug\\(.*\\.format\\(        (Python .format() even when debug disabled)\nlogger\\.debug\\(`                   (JS template literal even when debug disabled)\nlogger\\.debug\\(.*\\+.*\\+            (string concat for debug log)\nJSON\\.stringify\\(.*log             (JSON stringify for logging)\n```\n\n### Missing Structured Logging\n```\nconsole\\.log\\([\"'].*:.*[\"']        (unstructured string logging)\nprint\\(.*[\"'].*:.*[\"']             (unstructured print logging)\nlogger\\.\\w+\\([\"'].*[\"'] %         (format string logging vs structured)\n```\n\n### Synchronous Logging\n```\nfs\\.writeFileSync.*log             (sync file write for logging)\nfs\\.appendFileSync.*log            (sync file append for logging)\nopen\\(.*log.*\\)\\.write\\(          (Python: sync log file write)\n```\n\n### Missing Request/Trace IDs\n```\n# API handlers without correlation IDs\napp\\.(get|post)\\(.*req.*res       (check if request ID is propagated)\n@app\\.route\\(                      (check if request ID middleware exists)\n```\n\n### Metrics Collection Overhead\n```\n# Metrics in hot paths\n\\.observe\\(.*inside.*loop         (Prometheus observe in loop)\n\\.increment\\(.*inside.*loop       (counter increment in loop)\nstatsd\\..*inside.*loop            (StatsD in loop)\n\\.timing\\(.*inside.*loop          (timing metric in loop)\nDate\\.now\\(\\).*Date\\.now\\(\\)      (manual timing - use proper instrumentation)\nperformance\\.now\\(\\).*performance (manual performance timing)\n```\n\n## Improvement Strategies\n\n1. **Console.log**: Remove from production, use proper logger with levels\n2. **Log formatting**: Use lazy evaluation - logger.debug(\"msg %s\", expensive_value) vs f-strings\n3. **Structured logging**: Use JSON structured logs for machine parsing\n4. **Async logging**: Buffer and flush logs asynchronously, don't block request handling\n5. **Request IDs**: Add correlation ID middleware, propagate through all service calls\n6. **Metrics**: Pre-aggregate metrics, use histograms instead of per-request timers in hot loops\n","src/resources/skills/code-optimizer/references/memory-resources.md":"# Memory & Resource Management\n\n## Grep/Glob Patterns to Detect\n\n### Memory Leaks\n```\n# Event listeners never removed\naddEventListener.*without.*removeEventListener\n\\.on\\(.*without.*\\.off\\(\n\\.subscribe\\(.*without.*unsubscribe\n# Timers never cleared\nsetInterval\\(.*without.*clearInterval\nsetTimeout\\(.*without.*clearTimeout\n# Global/module-level caches without eviction\nglobal.*\\[\\]        (unbounded global arrays)\nglobal.*\\{\\}        (unbounded global dicts/objects)\nmodule\\.exports.*cache.*=.*\\{\\}\n_cache\\s*=\\s*\\{\\}   (module-level cache without LRU/TTL)\n# Closures retaining references\nclosure.*large.*object\n# React-specific\nuseEffect.*without.*cleanup\nuseRef.*large.*object\n```\n\n### Unclosed Resources\n```\nopen\\(.*without.*close\nopen\\(.*without.*with\\s   (Python: not using context manager)\nnew FileReader\\(.*without.*close\ncreateReadStream\\(.*without.*destroy\ncreateWriteStream\\(.*without.*end\nfs\\.open\\(.*without.*fs\\.close\nnew Socket\\(.*without.*\\.close\nnew WebSocket\\(.*without.*\\.close\nacquire\\(.*without.*release\n```\n\n### Large Allocations\n```\nnew Array\\(\\d{5,}       (arrays > 10k elements)\nBuffer\\.alloc\\(\\d{6,}   (buffers > 1MB)\n\\.fill\\(.*\\d{6,}        (filling large arrays)\n\\.repeat\\(\\d{4,}         (string repeat large count)\nJSON\\.parse\\(.*large     (parsing large JSON in memory)\n\\.readFileSync\\(          (synchronous large file reads)\n\\.readFile\\(.*without.*stream  (reading whole file vs streaming)\n```\n\n### String Concatenation in Loops\n```\n\\+=.*string.*for\n\\+=.*\\\".*loop\nstr\\s*\\+=              (Python string concat in loop)\n\\.join\\(\\[              (check if used correctly)\n```\n\n## Improvement Strategies\n\n1. **Event listeners**: Always pair add/remove, use AbortController for bulk cleanup\n2. **Timers**: Clear intervals in cleanup/unmount, use refs for timer IDs\n3. **Caches**: Use LRU cache with max size, add TTL, use WeakMap/WeakRef where possible\n4. **File handling**: Use context managers (Python with), try-finally, or using statements\n5. **Streams**: Use streaming for large data instead of loading everything in memory\n6. **String building**: Use StringBuilder/list join pattern instead of concatenation in loops\n7. **Buffers**: Pool and reuse buffers, use streaming transforms\n","src/resources/skills/code-optimizer/references/rendering-ui.md":"# Rendering & UI Performance\n\n## Grep/Glob Patterns to Detect\n\n### React Re-render Issues\n```\n# Missing memoization\nconst\\s+\\w+\\s*=\\s*\\(\\s*\\)\\s*=>.*return\\s*\\(    (inline component definitions)\n\\w+\\s*=\\s*\\{.*\\}.*prop=                          (object literal as prop - new ref every render)\n\\w+\\s*=\\s*\\[.*\\].*prop=                          (array literal as prop)\n\\w+\\s*=\\s*\\(\\).*=>.*prop=                        (arrow function as prop - new ref every render)\nstyle=\\{\\{                                        (inline style object)\n# Context causing re-renders\nuseContext\\(                                       (check context value stability)\n<\\w+Provider\\s+value=\\{\\{                         (new object in Provider value)\n<\\w+Provider\\s+value=\\{[^}]*\\}                    (unstable provider value)\n# State management\nuseState\\(.*\\{                                     (object state - check if needs splitting)\nsetState\\(.*\\{\\.\\.\\.state                          (spreading entire state on each update)\n```\n\n### Missing Virtualization\n```\n\\.map\\(.*<\\w+                  (rendering list items - check list size)\n{items\\.map\\(                  (JSX list rendering - check if >50 items)\n\\.map\\(.*return.*<li           (list rendering without virtualization)\n\\.map\\(.*return.*<tr           (table row rendering without virtualization)\n\\.map\\(.*return.*<div          (div list - check count)\nv-for=                         (Vue list rendering)\nngFor                          (Angular list rendering)\n```\n\n### Layout Thrashing\n```\noffsetWidth.*style\\.           (read then write in sequence)\noffsetHeight.*style\\.          (read then write)\ngetBoundingClientRect.*style   (read then write)\nclientWidth.*className         (read then class change)\nscrollTop.*style               (read then write)\n\\.style\\..*\\.style\\.           (multiple style writes - batch with class)\n```\n\n### Large DOM\n```\ndocument\\.createElement.*loop  (creating elements in loop)\ninnerHTML\\s*\\+=                (innerHTML concatenation - causes reparse)\n\\.appendChild\\(.*loop          (appending in loop without fragment)\ndocument\\.querySelector\\(.*loop (DOM query in loop)\n\\$\\(.*\\).*loop                 (jQuery selector in loop)\n```\n\n### Missing Lazy Loading\n```\n<img\\s+(?!.*loading)           (images without loading=\"lazy\")\n<iframe\\s+(?!.*loading)        (iframes without lazy loading)\nimport.*above.*fold            (heavy imports for below-fold content)\n```\n\n### Animation Performance\n```\n# Layout-triggering animations\nanimate.*width                 (animating width triggers layout)\nanimate.*height                (animating height triggers layout)\nanimate.*top                   (animating top triggers layout)\nanimate.*left                  (animating left triggers layout)\nanimate.*margin                (animating margin triggers layout)\ntransition.*width              (transitioning layout properties)\ntransition.*height\n# Should use transform/opacity instead\n@keyframes.*\\{.*(?:width|height|top|left|margin|padding)\n```\n\n### SSR/Hydration Issues\n```\nuseEffect\\(.*\\[\\].*setState   (client-side data fetch causing hydration mismatch)\ntypeof window                  (window checks indicating SSR issues)\ndocument\\.                     (direct document access in components)\nwindow\\.                       (direct window access in components)\n```\n\n## Improvement Strategies\n\n1. **Re-renders**: Use React.memo, useMemo, useCallback for stable references\n2. **Context**: Split contexts by update frequency, memoize provider values\n3. **Virtualization**: Use react-window/react-virtuoso for lists > 50 items\n4. **Layout thrashing**: Batch reads, then batch writes; use requestAnimationFrame\n5. **DOM manipulation**: Use DocumentFragment, batch insertions, avoid innerHTML +=\n6. **Lazy loading**: Add loading=\"lazy\" to images/iframes, use Intersection Observer\n7. **Animations**: Only animate transform and opacity (GPU-composited properties)\n8. **SSR**: Pre-fetch data server-side, avoid hydration mismatches\n","src/resources/skills/code-optimizer/references/security-performance.md":"# Security-Related Performance Issues\n\n## Grep/Glob Patterns to Detect\n\n### Cryptographic Misuse\n```\nmd5\\(                              (MD5 is fast but broken - use bcrypt/argon2 for passwords)\nsha1\\(                             (SHA1 is weak)\n\\.hashSync\\(.*rounds.*[1-5]\\b     (bcrypt with low rounds)\nDES\\b                              (DES is obsolete)\nMath\\.random\\(\\).*token            (Math.random for security tokens)\nMath\\.random\\(\\).*password         (Math.random for password generation)\nrandom\\.random\\(\\).*secret         (Python: insecure random for secrets)\n```\n\n### Expensive Security Operations in Hot Paths\n```\nbcrypt.*inside.*loop               (hashing in loop - expensive by design)\njwt\\.verify\\(.*inside.*loop        (JWT verification in loop)\nencrypt\\(.*inside.*loop            (encryption in loop)\n\\.hash\\(.*inside.*loop             (hashing in loop)\n```\n\n### Missing Rate Limiting\n```\napp\\.(get|post|put|delete)\\(       (routes without rate limiting)\n@app\\.route\\(                      (Flask routes without rate limiting)\nrouter\\.(get|post|put|delete)\\(    (Express routes without rate limiting)\n```\n\n### SQL Injection Vectors (Also Performance)\n```\nf\"SELECT.*\\{                       (Python f-string SQL)\nf\"INSERT.*\\{                       (Python f-string SQL)\n`SELECT.*\\$\\{                      (JS template literal SQL)\n\"SELECT.*\" \\+ \\w+                  (string concat SQL)\n'SELECT.*' \\+ \\w+                  (string concat SQL)\n\\.raw\\(.*\\+                        (raw query with concatenation)\n\\.execute\\(.*%.*%                  (Python format string SQL)\n```\n\n### ReDoS Vulnerable Patterns\n```\n\\(\\.\\*\\)\\+                         (catastrophic backtracking)\n\\(\\.\\+\\)\\+                         (catastrophic backtracking)\n\\([^)]*\\|[^)]*\\)\\+                (alternation with repetition)\n\\(\\[.*\\]\\+\\)\\+                    (nested quantifiers)\nnew RegExp\\(.*user                 (user input in regex)\nre\\.compile\\(.*user                (Python: user input in regex)\n```\n\n### N+1 Auth Checks\n```\n# Checking permissions inside loops\n\\.can\\(.*inside.*loop             (permission check in loop)\n\\.authorize\\(.*inside.*loop       (authorization in loop)\nisAllowed\\(.*inside.*loop         (permission check in loop)\nhasPermission\\(.*inside.*loop     (permission check in loop)\n```\n\n## Improvement Strategies\n\n1. **Crypto**: Use bcrypt/argon2 for passwords, SHA-256+ for hashing, crypto.randomBytes for tokens\n2. **Hot path crypto**: Cache JWT verification results, batch encrypt/decrypt\n3. **Rate limiting**: Add rate limiters (express-rate-limit, django-ratelimit, etc.)\n4. **SQL injection**: Use parameterized queries/prepared statements (also faster due to query plan caching)\n5. **ReDoS**: Audit regex patterns, use RE2 engine, set regex timeouts\n6. **Auth batching**: Batch permission checks, pre-load permissions per request\n","src/resources/skills/core-web-vitals/SKILL.md":"---\nname: core-web-vitals\ndescription: Optimize Core Web Vitals (LCP, INP, CLS) for better page experience and search ranking. Use when asked to \"improve Core Web Vitals\", \"fix LCP\", \"reduce CLS\", \"optimize INP\", \"page experience optimization\", or \"fix layout shifts\".\nlicense: MIT\nmetadata:\n  author: web-quality-skills\n  version: \"1.0\"\n---\n\n# Core Web Vitals optimization\n\nTargeted optimization for the three Core Web Vitals metrics that affect Google Search ranking and user experience.\n\n## The three metrics\n\n| Metric | Measures | Good | Needs work | Poor |\n|--------|----------|------|------------|------|\n| **LCP** | Loading | ≤ 2.5s | 2.5s – 4s | > 4s |\n| **INP** | Interactivity | ≤ 200ms | 200ms – 500ms | > 500ms |\n| **CLS** | Visual Stability | ≤ 0.1 | 0.1 – 0.25 | > 0.25 |\n\nGoogle measures at the **75th percentile** — 75% of page visits must meet \"Good\" thresholds.\n\n---\n\n## LCP: Largest Contentful Paint\n\nLCP measures when the largest visible content element renders. Usually this is:\n- Hero image or video\n- Large text block\n- Background image\n- `<svg>` element\n\n### Common LCP issues\n\n**1. Slow server response (TTFB > 800ms)**\n```\nFix: CDN, caching, optimized backend, edge rendering\n```\n\n**2. Render-blocking resources**\n```html\n<!-- ❌ Blocks rendering -->\n<link rel=\"stylesheet\" href=\"/all-styles.css\">\n\n<!-- ✅ Critical CSS inlined, rest deferred -->\n<style>/* Critical above-fold CSS */</style>\n<link rel=\"preload\" href=\"/styles.css\" as=\"style\" \n      onload=\"this.onload=null;this.rel='stylesheet'\">\n```\n\n**3. Slow resource load times**\n```html\n<!-- ❌ No hints, discovered late -->\n<img src=\"/hero.jpg\" alt=\"Hero\">\n\n<!-- ✅ Preloaded with high priority -->\n<link rel=\"preload\" href=\"/hero.webp\" as=\"image\" fetchpriority=\"high\">\n<img src=\"/hero.webp\" alt=\"Hero\" fetchpriority=\"high\">\n```\n\n**4. Client-side rendering delays**\n```javascript\n// ❌ Content loads after JavaScript\nuseEffect(() => {\n  fetch('/api/hero-text').then(r => r.json()).then(setHeroText);\n}, []);\n\n// ✅ Server-side or static rendering\n// Use SSR, SSG, or streaming to send HTML with content\nexport async function getServerSideProps() {\n  const heroText = await fetchHeroText();\n  return { props: { heroText } };\n}\n```\n\n### LCP optimization checklist\n\n```markdown\n- [ ] TTFB < 800ms (use CDN, edge caching)\n- [ ] LCP image preloaded with fetchpriority=\"high\"\n- [ ] LCP image optimized (WebP/AVIF, correct size)\n- [ ] Critical CSS inlined (< 14KB)\n- [ ] No render-blocking JavaScript in <head>\n- [ ] Fonts don't block text rendering (font-display: swap)\n- [ ] LCP element in initial HTML (not JS-rendered)\n```\n\n### LCP element identification\n```javascript\n// Find your LCP element\nnew PerformanceObserver((list) => {\n  const entries = list.getEntries();\n  const lastEntry = entries[entries.length - 1];\n  console.log('LCP element:', lastEntry.element);\n  console.log('LCP time:', lastEntry.startTime);\n}).observe({ type: 'largest-contentful-paint', buffered: true });\n```\n\n---\n\n## INP: Interaction to Next Paint\n\nINP measures responsiveness across ALL interactions (clicks, taps, key presses) during a page visit. It reports the worst interaction (at 98th percentile for high-traffic pages).\n\n### INP breakdown\n\nTotal INP = **Input Delay** + **Processing Time** + **Presentation Delay**\n\n| Phase | Target | Optimization |\n|-------|--------|--------------|\n| Input Delay | < 50ms | Reduce main thread blocking |\n| Processing | < 100ms | Optimize event handlers |\n| Presentation | < 50ms | Minimize rendering work |\n\n### Common INP issues\n\n**1. Long tasks blocking main thread**\n```javascript\n// ❌ Long synchronous task\nfunction processLargeArray(items) {\n  items.forEach(item => expensiveOperation(item));\n}\n\n// ✅ Break into chunks with yielding\nasync function processLargeArray(items) {\n  const CHUNK_SIZE = 100;\n  for (let i = 0; i < items.length; i += CHUNK_SIZE) {\n    const chunk = items.slice(i, i + CHUNK_SIZE);\n    chunk.forEach(item => expensiveOperation(item));\n    \n    // Yield to main thread\n    await new Promise(r => setTimeout(r, 0));\n    // Or use scheduler.yield() when available\n  }\n}\n```\n\n**2. Heavy event handlers**\n```javascript\n// ❌ All work in handler\nbutton.addEventListener('click', () => {\n  // Heavy computation\n  const result = calculateComplexThing();\n  // DOM updates\n  updateUI(result);\n  // Analytics\n  trackEvent('click');\n});\n\n// ✅ Prioritize visual feedback\nbutton.addEventListener('click', () => {\n  // Immediate visual feedback\n  button.classList.add('loading');\n  \n  // Defer non-critical work\n  requestAnimationFrame(() => {\n    const result = calculateComplexThing();\n    updateUI(result);\n  });\n  \n  // Use requestIdleCallback for analytics\n  requestIdleCallback(() => trackEvent('click'));\n});\n```\n\n**3. Third-party scripts**\n```javascript\n// ❌ Eagerly loaded, blocks interactions\n<script src=\"https://heavy-widget.com/widget.js\"></script>\n\n// ✅ Lazy loaded on interaction or visibility\nconst loadWidget = () => {\n  import('https://heavy-widget.com/widget.js')\n    .then(widget => widget.init());\n};\nbutton.addEventListener('click', loadWidget, { once: true });\n```\n\n**4. Excessive re-renders (React/Vue)**\n```javascript\n// ❌ Re-renders entire tree\nfunction App() {\n  const [count, setCount] = useState(0);\n  return (\n    <div>\n      <Counter count={count} />\n      <ExpensiveComponent /> {/* Re-renders on every count change */}\n    </div>\n  );\n}\n\n// ✅ Memoized expensive components\nconst MemoizedExpensive = React.memo(ExpensiveComponent);\n\nfunction App() {\n  const [count, setCount] = useState(0);\n  return (\n    <div>\n      <Counter count={count} />\n      <MemoizedExpensive />\n    </div>\n  );\n}\n```\n\n### INP optimization checklist\n\n```markdown\n- [ ] No tasks > 50ms on main thread\n- [ ] Event handlers complete quickly (< 100ms)\n- [ ] Visual feedback provided immediately\n- [ ] Heavy work deferred with requestIdleCallback\n- [ ] Third-party scripts don't block interactions\n- [ ] Debounced input handlers where appropriate\n- [ ] Web Workers for CPU-intensive operations\n```\n\n### INP debugging\n```javascript\n// Identify slow interactions\nnew PerformanceObserver((list) => {\n  for (const entry of list.getEntries()) {\n    if (entry.duration > 200) {\n      console.warn('Slow interaction:', {\n        type: entry.name,\n        duration: entry.duration,\n        processingStart: entry.processingStart,\n        processingEnd: entry.processingEnd,\n        target: entry.target\n      });\n    }\n  }\n}).observe({ type: 'event', buffered: true, durationThreshold: 16 });\n```\n\n---\n\n## CLS: Cumulative Layout Shift\n\nCLS measures unexpected layout shifts. A shift occurs when a visible element changes position between frames without user interaction.\n\n**CLS Formula:** `impact fraction × distance fraction`\n\n### Common CLS causes\n\n**1. Images without dimensions**\n```html\n<!-- ❌ Causes layout shift when loaded -->\n<img src=\"photo.jpg\" alt=\"Photo\">\n\n<!-- ✅ Space reserved -->\n<img src=\"photo.jpg\" alt=\"Photo\" width=\"800\" height=\"600\">\n\n<!-- ✅ Or use aspect-ratio -->\n<img src=\"photo.jpg\" alt=\"Photo\" style=\"aspect-ratio: 4/3; width: 100%;\">\n```\n\n**2. Ads, embeds, and iframes**\n```html\n<!-- ❌ Unknown size until loaded -->\n<iframe src=\"https://ad-network.com/ad\"></iframe>\n\n<!-- ✅ Reserve space with min-height -->\n<div style=\"min-height: 250px;\">\n  <iframe src=\"https://ad-network.com/ad\" height=\"250\"></iframe>\n</div>\n\n<!-- ✅ Or use aspect-ratio container -->\n<div style=\"aspect-ratio: 16/9;\">\n  <iframe src=\"https://youtube.com/embed/...\" \n          style=\"width: 100%; height: 100%;\"></iframe>\n</div>\n```\n\n**3. Dynamically injected content**\n```javascript\n// ❌ Inserts content above viewport\nnotifications.prepend(newNotification);\n\n// ✅ Insert below viewport or use transform\nconst insertBelow = viewport.bottom < newNotification.top;\nif (insertBelow) {\n  notifications.prepend(newNotification);\n} else {\n  // Animate in without shifting\n  newNotification.style.transform = 'translateY(-100%)';\n  notifications.prepend(newNotification);\n  requestAnimationFrame(() => {\n    newNotification.style.transform = '';\n  });\n}\n```\n\n**4. Web fonts causing FOUT**\n```css\n/* ❌ Font swap shifts text */\n@font-face {\n  font-family: 'Custom';\n  src: url('custom.woff2') format('woff2');\n}\n\n/* ✅ Optional font (no shift if slow) */\n@font-face {\n  font-family: 'Custom';\n  src: url('custom.woff2') format('woff2');\n  font-display: optional;\n}\n\n/* ✅ Or match fallback metrics */\n@font-face {\n  font-family: 'Custom';\n  src: url('custom.woff2') format('woff2');\n  font-display: swap;\n  size-adjust: 105%; /* Match fallback size */\n  ascent-override: 95%;\n  descent-override: 20%;\n}\n```\n\n**5. Animations triggering layout**\n```css\n/* ❌ Animates layout properties */\n.animate {\n  transition: height 0.3s, width 0.3s;\n}\n\n/* ✅ Use transform instead */\n.animate {\n  transition: transform 0.3s;\n}\n.animate.expanded {\n  transform: scale(1.2);\n}\n```\n\n### CLS optimization checklist\n\n```markdown\n- [ ] All images have width/height or aspect-ratio\n- [ ] All videos/embeds have reserved space\n- [ ] Ads have min-height containers\n- [ ] Fonts use font-display: optional or matched metrics\n- [ ] Dynamic content inserted below viewport\n- [ ] Animations use transform/opacity only\n- [ ] No content injected above existing content\n```\n\n### CLS debugging\n```javascript\n// Track layout shifts\nnew PerformanceObserver((list) => {\n  for (const entry of list.getEntries()) {\n    if (!entry.hadRecentInput) {\n      console.log('Layout shift:', entry.value);\n      entry.sources?.forEach(source => {\n        console.log('  Shifted element:', source.node);\n        console.log('  Previous rect:', source.previousRect);\n        console.log('  Current rect:', source.currentRect);\n      });\n    }\n  }\n}).observe({ type: 'layout-shift', buffered: true });\n```\n\n---\n\n## Measurement tools\n\n### Lab testing\n- **Chrome DevTools** → Performance panel, Lighthouse\n- **WebPageTest** → Detailed waterfall, filmstrip\n- **Lighthouse CLI** → `npx lighthouse <url>`\n\n### Field data (real users)\n- **Chrome User Experience Report (CrUX)** → BigQuery or API\n- **Search Console** → Core Web Vitals report\n- **web-vitals library** → Send to your analytics\n\n```javascript\nimport {onLCP, onINP, onCLS} from 'web-vitals';\n\nfunction sendToAnalytics({name, value, rating}) {\n  gtag('event', name, {\n    event_category: 'Web Vitals',\n    value: Math.round(name === 'CLS' ? value * 1000 : value),\n    event_label: rating\n  });\n}\n\nonLCP(sendToAnalytics);\nonINP(sendToAnalytics);\nonCLS(sendToAnalytics);\n```\n\n---\n\n## Framework quick fixes\n\n### Next.js\n```jsx\n// LCP: Use next/image with priority\nimport Image from 'next/image';\n<Image src=\"/hero.jpg\" priority fill alt=\"Hero\" />\n\n// INP: Use dynamic imports\nconst HeavyComponent = dynamic(() => import('./Heavy'), { ssr: false });\n\n// CLS: Image component handles dimensions automatically\n```\n\n### React\n```jsx\n// LCP: Preload in head\n<link rel=\"preload\" href=\"/hero.jpg\" as=\"image\" fetchpriority=\"high\" />\n\n// INP: Memoize and useTransition\nconst [isPending, startTransition] = useTransition();\nstartTransition(() => setExpensiveState(newValue));\n\n// CLS: Always specify dimensions in img tags\n```\n\n### Vue/Nuxt\n```vue\n<!-- LCP: Use nuxt/image with preload -->\n<NuxtImg src=\"/hero.jpg\" preload loading=\"eager\" />\n\n<!-- INP: Use async components -->\n<component :is=\"() => import('./Heavy.vue')\" />\n\n<!-- CLS: Use aspect-ratio CSS -->\n<img :style=\"{ aspectRatio: '16/9' }\" />\n```\n\n## References\n\n- [web.dev LCP](https://web.dev/articles/lcp)\n- [web.dev INP](https://web.dev/articles/inp)\n- [web.dev CLS](https://web.dev/articles/cls)\n- [Code Optimizer skill](../code-optimizer/SKILL.md)\n","src/resources/skills/core-web-vitals/references/LCP.md":"# LCP optimization reference\n\n## What is LCP?\n\nLargest Contentful Paint (LCP) measures when the largest content element in the viewport becomes visible. This is typically:\n\n- An `<img>` element\n- An `<image>` element inside `<svg>`\n- A `<video>` element with poster image\n- An element with a background image via `url()`\n- A block-level element containing text nodes\n\n## LCP timeline\n\n```\n[  Server Response  ][  Resource Load  ][  Render  ]\n       TTFB              Download         Paint\n       └─────────────────────────────────────┘\n                         LCP Time\n```\n\n## Detailed optimizations\n\n### 1. Server response time (TTFB)\n\nTarget: < 800ms\n\n**Causes:**\n- Slow server/database queries\n- No CDN/edge caching\n- Inefficient backend code\n- Cold starts (serverless)\n\n**Solutions:**\n```javascript\n// Use edge functions for dynamic content\n// Vercel example\nexport const config = { runtime: 'edge' };\n\n// Use stale-while-revalidate caching\n// Cache-Control header\nres.setHeader('Cache-Control', 's-maxage=60, stale-while-revalidate=300');\n```\n\n### 2. Resource load time\n\n**For images:**\n```html\n<!-- Preload LCP image -->\n<link rel=\"preload\" as=\"image\" href=\"/hero.webp\" \n      imagesrcset=\"/hero-400.webp 400w, /hero-800.webp 800w\"\n      imagesizes=\"100vw\"\n      fetchpriority=\"high\">\n\n<!-- Modern format with fallback -->\n<picture>\n  <source srcset=\"/hero.avif\" type=\"image/avif\">\n  <source srcset=\"/hero.webp\" type=\"image/webp\">\n  <img src=\"/hero.jpg\" width=\"1200\" height=\"600\" \n       fetchpriority=\"high\" alt=\"Hero\">\n</picture>\n```\n\n**For text (web fonts):**\n```css\n@font-face {\n  font-family: 'Heading';\n  src: url('/fonts/heading.woff2') format('woff2');\n  font-display: swap; /* Show fallback immediately */\n}\n```\n\n### 3. Render blocking resources\n\n**Critical CSS pattern:**\n```html\n<head>\n  <!-- Inline critical CSS -->\n  <style>\n    /* Only above-fold styles, < 14KB */\n    .hero { /* ... */ }\n    .nav { /* ... */ }\n  </style>\n  \n  <!-- Defer non-critical CSS -->\n  <link rel=\"preload\" href=\"/styles.css\" as=\"style\" \n        onload=\"this.onload=null;this.rel='stylesheet'\">\n</head>\n```\n\n**Defer JavaScript:**\n```html\n<!-- ❌ Blocks parsing -->\n<script src=\"/app.js\"></script>\n\n<!-- ✅ Deferred (runs after HTML parsed) -->\n<script defer src=\"/app.js\"></script>\n\n<!-- ✅ Module (deferred by default) -->\n<script type=\"module\" src=\"/app.mjs\"></script>\n```\n\n### 4. Client-side rendering\n\n**Problem:** Content not in initial HTML.\n\n**Solutions:**\n\n**Server-side rendering (SSR):**\n```javascript\n// Next.js\nexport async function getServerSideProps() {\n  const data = await fetchHeroContent();\n  return { props: { hero: data } };\n}\n```\n\n**Static site generation (SSG):**\n```javascript\n// Next.js\nexport async function getStaticProps() {\n  const data = await fetchHeroContent();\n  return { props: { hero: data }, revalidate: 3600 };\n}\n```\n\n**Streaming SSR:**\n```jsx\n// React 18+\nimport { Suspense } from 'react';\n\nfunction Page() {\n  return (\n    <Suspense fallback={<HeroSkeleton />}>\n      <Hero />\n    </Suspense>\n  );\n}\n```\n\n## Framework-specific tips\n\n### Next.js\n```jsx\nimport Image from 'next/image';\n\n// LCP image with priority\n<Image \n  src=\"/hero.jpg\"\n  priority\n  fill\n  sizes=\"100vw\"\n  alt=\"Hero\"\n/>\n```\n\n### Nuxt\n```vue\n<NuxtImg\n  src=\"/hero.jpg\"\n  preload\n  loading=\"eager\"\n  sizes=\"100vw\"\n/>\n```\n\n### Astro\n```astro\n---\nimport { Image } from 'astro:assets';\nimport hero from '../assets/hero.jpg';\n---\n<Image \n  src={hero} \n  loading=\"eager\" \n  decoding=\"sync\"\n  alt=\"Hero\" \n/>\n```\n\n## Debugging LCP\n\n```javascript\n// Identify LCP element\nnew PerformanceObserver((entryList) => {\n  const entries = entryList.getEntries();\n  const lastEntry = entries[entries.length - 1];\n  \n  console.log('LCP:', {\n    element: lastEntry.element,\n    time: lastEntry.startTime,\n    size: lastEntry.size,\n    url: lastEntry.url,\n    renderTime: lastEntry.renderTime,\n    loadTime: lastEntry.loadTime\n  });\n}).observe({ type: 'largest-contentful-paint', buffered: true });\n```\n\n## Common issues\n\n| Issue | Impact | Fix |\n|-------|--------|-----|\n| No preload for LCP image | +500-1000ms | Add `<link rel=\"preload\">` |\n| Large unoptimized image | +300-800ms | Compress, use WebP/AVIF |\n| Render-blocking CSS | +200-500ms | Inline critical CSS |\n| Slow TTFB | +300-2000ms | CDN, edge caching |\n| Client-rendered content | +500-2000ms | SSR/SSG |\n","src/resources/skills/create-gsd-extension/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2FSKILL.md -->","src/resources/skills/create-gsd-extension/references/compaction-session-control.md":"<overview>\nCustom compaction hooks, triggering compaction, and session control methods available only in command handlers.\n</overview>\n\n<custom_compaction>\nOverride default compaction behavior:\n\n```typescript\npi.on(\"session_before_compact\", async (event, ctx) => {\n  const { preparation, branchEntries, customInstructions, signal } = event;\n\n  // Option 1: Cancel\n  return { cancel: true };\n\n  // Option 2: Custom summary\n  return {\n    compaction: {\n      summary: \"Custom summary of conversation so far...\",\n      firstKeptEntryId: preparation.firstKeptEntryId,\n      tokensBefore: preparation.tokensBefore,\n    }\n  };\n});\n```\n</custom_compaction>\n\n<trigger_compaction>\nTrigger compaction programmatically from any handler:\n\n```typescript\nctx.compact({\n  customInstructions: \"Focus on the authentication changes\",\n  onComplete: (result) => ctx.ui.notify(\"Compacted!\", \"info\"),\n  onError: (error) => ctx.ui.notify(`Failed: ${error.message}`, \"error\"),\n});\n```\n</trigger_compaction>\n\n<session_control>\n**Only available in command handlers** (deadlocks in event handlers):\n\n```typescript\npi.registerCommand(\"handoff\", {\n  handler: async (args, ctx) => {\n    await ctx.waitForIdle();\n\n    // Create new session with initial context\n    const result = await ctx.newSession({\n      parentSession: ctx.sessionManager.getSessionFile(),\n      setup: async (sm) => {\n        sm.appendMessage({\n          role: \"user\",\n          content: [{ type: \"text\", text: `Context: ${args}` }],\n          timestamp: Date.now(),\n        });\n      },\n    });\n\n    if (result.cancelled) { /* extension cancelled via session_before_switch */ }\n  },\n});\n```\n\n| Method | Purpose |\n|--------|---------|\n| `ctx.waitForIdle()` | Wait for agent to finish streaming |\n| `ctx.newSession(options?)` | Create a new session |\n| `ctx.fork(entryId)` | Fork from a specific entry |\n| `ctx.navigateTree(targetId, options?)` | Navigate session tree (with optional summary) |\n| `ctx.reload()` | Hot-reload everything (treat as terminal — code after runs pre-reload version) |\n\n`navigateTree` options:\n- `summarize: boolean` — generate summary of abandoned branch\n- `customInstructions: string` — instructions for summarizer\n- `replaceInstructions: boolean` — replace default prompt entirely\n- `label: string` — label to attach to branch summary\n</session_control>\n","src/resources/skills/create-gsd-extension/references/custom-commands.md":"<overview>\nCustom slash commands — registration, argument completions, subcommand patterns, and the extended command context.\n</overview>\n\n<basic_registration>\n```typescript\npi.registerCommand(\"deploy\", {\n  description: \"Deploy to an environment\",\n  handler: async (args, ctx) => {\n    // args = everything after \"/deploy \"\n    // ctx = ExtensionCommandContext (has session control methods)\n    ctx.ui.notify(`Deploying to ${args || \"production\"}`, \"info\");\n  },\n});\n```\n</basic_registration>\n\n<argument_completions>\nAdd tab-completion for command arguments:\n\n```typescript\nimport type { AutocompleteItem } from \"@gsd/pi-tui\";\n\npi.registerCommand(\"deploy\", {\n  description: \"Deploy to an environment\",\n  getArgumentCompletions: (prefix: string): AutocompleteItem[] | null => {\n    const envs = [\"dev\", \"staging\", \"prod\"];\n    const items = envs.map(e => ({ value: e, label: e }));\n    const filtered = items.filter(i => i.value.startsWith(prefix));\n    return filtered.length > 0 ? filtered : null;\n  },\n  handler: async (args, ctx) => {\n    ctx.ui.notify(`Deploying to ${args}`, \"info\");\n  },\n});\n```\n</argument_completions>\n\n<subcommand_pattern>\nFake nested commands via first-argument parsing. Used by `/wt new|ls|switch|merge|rm`.\n\n```typescript\npi.registerCommand(\"foo\", {\n  description: \"Manage foo items: /foo new|list|delete [name]\",\n\n  getArgumentCompletions: (prefix: string) => {\n    const parts = prefix.trim().split(/\\s+/);\n\n    // First arg: subcommand\n    if (parts.length <= 1) {\n      return [\"new\", \"list\", \"delete\"]\n        .filter(cmd => cmd.startsWith(parts[0] ?? \"\"))\n        .map(cmd => ({ value: cmd, label: cmd }));\n    }\n\n    // Second arg: depends on subcommand\n    if (parts[0] === \"delete\") {\n      const items = getItemsSomehow();\n      return items\n        .filter(name => name.startsWith(parts[1] ?? \"\"))\n        .map(name => ({ value: `delete ${name}`, label: name }));\n    }\n\n    return [];\n  },\n\n  handler: async (args, ctx) => {\n    const parts = args.trim().split(/\\s+/);\n    const sub = parts[0];\n\n    switch (sub) {\n      case \"new\": /* ... */ return;\n      case \"list\": /* ... */ return;\n      case \"delete\": /* handle parts[1] */ return;\n      default:\n        ctx.ui.notify(\"Usage: /foo <new|list|delete> [name]\", \"info\");\n    }\n  },\n});\n```\n\n**Gotcha:** `\"\".trim().split(/\\s+/)` produces `['']`, not `[]`. That's why `parts.length <= 1` handles both empty and partial first arg.\n</subcommand_pattern>\n\n<command_context>\nCommand handlers get `ExtensionCommandContext` which extends `ExtensionContext` with session control methods:\n\n| Method | Purpose |\n|--------|---------|\n| `ctx.waitForIdle()` | Wait for agent to finish streaming |\n| `ctx.newSession(options?)` | Create a new session |\n| `ctx.fork(entryId)` | Fork from an entry |\n| `ctx.navigateTree(targetId, options?)` | Navigate session tree |\n| `ctx.reload()` | Hot-reload everything |\n\n**⚠️ These methods are ONLY available in command handlers.** Calling them from event handlers causes deadlocks.\n\n```typescript\npi.registerCommand(\"handoff\", {\n  handler: async (args, ctx) => {\n    await ctx.waitForIdle();\n    await ctx.newSession({\n      setup: async (sm) => {\n        sm.appendMessage({\n          role: \"user\",\n          content: [{ type: \"text\", text: `Context: ${args}` }],\n          timestamp: Date.now(),\n        });\n      },\n    });\n  },\n});\n```\n</command_context>\n\n<reload_pattern>\nExpose reload as both a command and a tool the LLM can call:\n\n```typescript\npi.registerCommand(\"reload-runtime\", {\n  description: \"Reload extensions, skills, prompts, and themes\",\n  handler: async (_args, ctx) => {\n    await ctx.reload();\n    return;  // Treat reload as terminal\n  },\n});\n\npi.registerTool({\n  name: \"reload_runtime\",\n  label: \"Reload Runtime\",\n  description: \"Reload extensions, skills, prompts, and themes\",\n  parameters: Type.Object({}),\n  async execute() {\n    pi.sendUserMessage(\"/reload-runtime\", { deliverAs: \"followUp\" });\n    return { content: [{ type: \"text\", text: \"Queued /reload-runtime as follow-up.\" }] };\n  },\n});\n```\n</reload_pattern>\n","src/resources/skills/create-gsd-extension/references/custom-rendering.md":"<overview>\nCustom rendering for tools and messages — control how they appear in the TUI.\n</overview>\n\n<tool_rendering>\nTools can provide `renderCall` (how the call looks) and `renderResult` (how the result looks):\n\n```typescript\nimport { Text } from \"@gsd/pi-tui\";\nimport { keyHint } from \"@gsd/pi-coding-agent\";\n\npi.registerTool({\n  name: \"my_tool\",\n  // ...\n\n  renderCall(args, theme) {\n    let text = theme.fg(\"toolTitle\", theme.bold(\"my_tool \"));\n    text += theme.fg(\"muted\", args.action);\n    if (args.text) text += \" \" + theme.fg(\"dim\", `\"${args.text}\"`);\n    return new Text(text, 0, 0);  // 0,0 padding — Box handles it\n  },\n\n  renderResult(result, { expanded, isPartial }, theme) {\n    // isPartial = true during streaming (onUpdate was called)\n    if (isPartial) {\n      return new Text(theme.fg(\"warning\", \"Processing...\"), 0, 0);\n    }\n\n    // expanded = user toggled expand (Ctrl+O)\n    if (result.details?.error) {\n      return new Text(theme.fg(\"error\", `Error: ${result.details.error}`), 0, 0);\n    }\n\n    let text = theme.fg(\"success\", \"✓ Done\");\n    if (!expanded) {\n      text += ` (${keyHint(\"expandTools\", \"to expand\")})`;\n    }\n    if (expanded && result.details?.items) {\n      for (const item of result.details.items) {\n        text += \"\\n  \" + theme.fg(\"dim\", item);\n      }\n    }\n    return new Text(text, 0, 0);\n  },\n});\n```\n\nIf you omit `renderCall`/`renderResult`, the built-in renderer is used. Useful for tool overrides where you just wrap logic without reimplementing UI.\n\n**Fallback:** If render methods throw, `renderCall` shows tool name, `renderResult` shows raw `content` text.\n</tool_rendering>\n\n<key_hints>\nKey hint helpers for showing keybinding info in render output:\n\n```typescript\nimport { keyHint, appKeyHint, editorKey, rawKeyHint } from \"@gsd/pi-coding-agent\";\n\n// Editor action hint (respects user keybinding config)\nkeyHint(\"expandTools\", \"to expand\")    // e.g., \"Ctrl+O to expand\"\nkeyHint(\"selectConfirm\", \"to select\")\n\n// Raw key hint (always shows literal key)\nrawKeyHint(\"Ctrl+O\", \"to expand\")\n```\n</key_hints>\n\n<message_rendering>\nRegister a renderer for custom message types:\n\n```typescript\nimport { Text } from \"@gsd/pi-tui\";\n\npi.registerMessageRenderer(\"my-extension\", (message, options, theme) => {\n  const { expanded } = options;\n  let text = theme.fg(\"accent\", `[${message.customType}] `) + message.content;\n  if (expanded && message.details) {\n    text += \"\\n\" + theme.fg(\"dim\", JSON.stringify(message.details, null, 2));\n  }\n  return new Text(text, 0, 0);\n});\n\n// Send messages that use this renderer:\npi.sendMessage({\n  customType: \"my-extension\",  // Matches renderer name\n  content: \"Status update\",\n  display: true,\n  details: { foo: \"bar\" },\n});\n```\n</message_rendering>\n\n<syntax_highlighting>\n```typescript\nimport { highlightCode, getLanguageFromPath } from \"@gsd/pi-coding-agent\";\n\nconst lang = getLanguageFromPath(\"/path/to/file.rs\");  // \"rust\"\nconst highlighted = highlightCode(code, lang, theme);\n```\n</syntax_highlighting>\n\n<best_practices>\n- Return `Text` with padding `(0, 0)` — the wrapping `Box` handles padding\n- Support `expanded` for detail on demand\n- Handle `isPartial` for streaming progress\n- Keep collapsed view compact\n- Use `\\n` for multi-line content within a single `Text`\n</best_practices>\n","src/resources/skills/create-gsd-extension/references/custom-tools.md":"<overview>\nComplete custom tools reference — registration, parameters, execution, output truncation, overrides, rendering, and dynamic registration.\n</overview>\n\n<registration>\n```typescript\nimport { Type } from \"@sinclair/typebox\";\nimport { StringEnum } from \"@gsd/pi-ai\";\n\npi.registerTool({\n  name: \"my_tool\",                    // Unique identifier (snake_case)\n  label: \"My Tool\",                   // Display name in TUI\n  description: \"What this does\",      // Full description shown to LLM\n\n  // Optional: one-liner for system prompt \"Available tools\" section\n  promptSnippet: \"Manage project todo items\",\n\n  // Optional: bullets added to system prompt \"Guidelines\" when tool is active\n  promptGuidelines: [\n    \"Use my_tool for task management instead of file edits.\"\n  ],\n\n  // Parameter schema (MUST use TypeBox)\n  parameters: Type.Object({\n    action: StringEnum([\"list\", \"add\", \"remove\"] as const),\n    text: Type.Optional(Type.String({ description: \"Item text\" })),\n    id: Type.Optional(Type.Number({ description: \"Item ID\" })),\n  }),\n\n  async execute(toolCallId, params, signal, onUpdate, ctx) {\n    // 1. Check cancellation\n    if (signal?.aborted) {\n      return { content: [{ type: \"text\", text: \"Cancelled\" }] };\n    }\n\n    // 2. Stream progress (optional)\n    onUpdate?.({\n      content: [{ type: \"text\", text: \"Working...\" }],\n      details: { progress: 50 },\n    });\n\n    // 3. Do the work\n    const result = await doWork(params);\n\n    // 4. Return result\n    return {\n      content: [{ type: \"text\", text: \"Result text for LLM\" }],  // Sent to LLM context\n      details: { data: result },                                   // For rendering & state\n    };\n  },\n\n  // Optional: custom TUI rendering\n  renderCall(args, theme) { ... },\n  renderResult(result, { expanded, isPartial }, theme) { ... },\n});\n```\n</registration>\n\n<critical_stringenum>\n**⚠️ MUST use `StringEnum` for string enum parameters:**\n\n```typescript\nimport { StringEnum } from \"@gsd/pi-ai\";\n\n// ✅ Correct — works with all providers including Google\naction: StringEnum([\"list\", \"add\", \"remove\"] as const)\n\n// ❌ BROKEN with Google's API\naction: Type.Union([Type.Literal(\"list\"), Type.Literal(\"add\")])\n```\n</critical_stringenum>\n\n<output_truncation>\nTools MUST truncate output to avoid context overflow. Built-in limit: 50KB / 2000 lines.\n\n```typescript\nimport {\n  truncateHead, truncateTail, formatSize,\n  DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES,\n} from \"@gsd/pi-coding-agent\";\n\nasync execute(toolCallId, params, signal, onUpdate, ctx) {\n  const output = await runCommand();\n  const truncation = truncateHead(output, {\n    maxLines: DEFAULT_MAX_LINES,\n    maxBytes: DEFAULT_MAX_BYTES,\n  });\n\n  let result = truncation.content;\n  if (truncation.truncated) {\n    const tempFile = writeTempFile(output);\n    result += `\\n\\n[Output truncated: ${truncation.outputLines}/${truncation.totalLines} lines`;\n    result += ` (${formatSize(truncation.outputBytes)}/${formatSize(truncation.totalBytes)}).`;\n    result += ` Full output: ${tempFile}]`;\n  }\n  return { content: [{ type: \"text\", text: result }] };\n}\n```\n\nUse `truncateHead` when beginning matters (search results, file reads). Use `truncateTail` when end matters (logs, command output).\n</output_truncation>\n\n<signaling_errors>\nThrow to signal an error (sets `isError: true`). Returning a value never sets error flag.\n\n```typescript\nasync execute(toolCallId, params) {\n  if (!isValid(params.input)) {\n    throw new Error(`Invalid input: ${params.input}`);\n  }\n  return { content: [{ type: \"text\", text: \"OK\" }], details: {} };\n}\n```\n</signaling_errors>\n\n<dynamic_registration>\nTools can be registered at any time — during load, in `session_start`, in command handlers. Available immediately without `/reload`.\n\n```typescript\npi.on(\"session_start\", async (_event, ctx) => {\n  pi.registerTool({ name: \"dynamic_tool\", ... });\n});\n```\n\nUse `pi.setActiveTools(names)` to enable/disable tools at runtime.\n</dynamic_registration>\n\n<overriding_builtins>\nRegister a tool with the same name as a built-in (`read`, `bash`, `edit`, `write`, `grep`, `find`, `ls`) to override it. **Must match exact result shape including `details` type.**\n\n```typescript\nimport { createReadTool } from \"@gsd/pi-coding-agent\";\n\npi.registerTool({\n  name: \"read\",\n  label: \"Read (Logged)\",\n  description: \"Read file contents with logging\",\n  parameters: Type.Object({\n    path: Type.String(),\n    offset: Type.Optional(Type.Number()),\n    limit: Type.Optional(Type.Number()),\n  }),\n  async execute(toolCallId, params, signal, onUpdate, ctx) {\n    console.log(`[AUDIT] Reading: ${params.path}`);\n    const builtIn = createReadTool(ctx.cwd);\n    return builtIn.execute(toolCallId, params, signal, onUpdate);\n  },\n  // Omit renderCall/renderResult to use built-in renderer\n});\n```\n\nStart with no built-in tools: `gsd --no-tools -e ./my-extension.ts`\n</overriding_builtins>\n\n<multiple_tools>\nOne extension can register multiple tools with shared state:\n\n```typescript\nexport default function (pi: ExtensionAPI) {\n  let connection = null;\n\n  pi.registerTool({ name: \"db_connect\", ... });\n  pi.registerTool({ name: \"db_query\", ... });\n  pi.registerTool({ name: \"db_close\", ... });\n\n  pi.on(\"session_shutdown\", async () => {\n    connection?.close();\n  });\n}\n```\n</multiple_tools>\n\n<path_normalization>\nSome models add `@` prefix to path arguments. Strip it:\n\n```typescript\nasync execute(toolCallId, params, signal, onUpdate, ctx) {\n  let path = params.path;\n  if (path.startsWith(\"@\")) path = path.slice(1);\n  // ...\n}\n```\n</path_normalization>\n","src/resources/skills/create-gsd-extension/references/custom-ui.md":"<overview>\nComplete custom UI reference — dialogs, persistent elements, custom components, overlays, custom editors, built-in components, keyboard input, performance, theming, and common mistakes.\n</overview>\n\n<ui_architecture>\n```\n┌─────────────────────────────────────────────────┐\n│  Custom Header (ctx.ui.setHeader)               │\n├─────────────────────────────────────────────────┤\n│  Message Area                                   │\n│  - User/assistant messages                      │\n│  - Tool calls ◄── renderCall/renderResult       │\n│  - Custom messages ◄── registerMessageRenderer  │\n├─────────────────────────────────────────────────┤\n│  Widgets (above editor) ◄── ctx.ui.setWidget    │\n├─────────────────────────────────────────────────┤\n│  Editor ◄── ctx.ui.custom() / setEditorComponent│\n├─────────────────────────────────────────────────┤\n│  Widgets (below editor) ◄── ctx.ui.setWidget    │\n├─────────────────────────────────────────────────┤\n│  Footer ◄── ctx.ui.setFooter / setStatus        │\n└─────────────────────────────────────────────────┘\n  ┌─────────────────────┐\n  │  Overlay (floating)  │ ◄── ctx.ui.custom({ overlay })\n  └─────────────────────┘\n```\n\n**11 ways to get UI on screen:**\n\n| Method | Blocks? | Replaces editor? |\n|--------|---------|-------------------|\n| `ctx.ui.select/confirm/input/editor` | Yes | Temporarily |\n| `ctx.ui.notify` | No | No |\n| `ctx.ui.setStatus` | No | No (footer) |\n| `ctx.ui.setWidget` | No | No |\n| `ctx.ui.setFooter` | No | No (replaces footer) |\n| `ctx.ui.setHeader` | No | No (replaces header) |\n| `ctx.ui.custom()` | Yes | Temporarily |\n| `ctx.ui.custom({overlay})` | Yes | No (renders on top) |\n| `ctx.ui.setEditorComponent` | No | Yes (permanently) |\n| `renderCall/renderResult` | No | No (inline in messages) |\n| `registerMessageRenderer` | No | No (inline in messages) |\n</ui_architecture>\n\n<component_interface>\nEvery visual element implements:\n\n```typescript\ninterface Component {\n  render(width: number): string[];   // Required — each line ≤ width visible chars\n  handleInput?(data: string): void;  // Optional — receive keyboard input\n  wantsKeyRelease?: boolean;         // Optional — receive key release events (Kitty protocol)\n  invalidate(): void;                // Required — clear cached render state\n}\n```\n\n**Render contract:**\n- Return array of strings, one per line\n- Each string MUST NOT exceed `width` in visible characters\n- ANSI escape codes don't count toward visible width\n- **Styles are reset at end of each line** — reapply per line\n- Return `[]` for zero-height component\n\n**Invalidation contract:**\n- Clear ALL cached render output\n- Clear any pre-baked themed strings\n- Call `super.invalidate()` if extending a built-in component\n</component_interface>\n\n<dialogs>\nBlocking dialog methods on `ctx.ui`:\n\n```typescript\nconst choice = await ctx.ui.select(\"Pick one:\", [\"A\", \"B\", \"C\"]);       // string | undefined\nconst ok = await ctx.ui.confirm(\"Delete?\", \"This cannot be undone\");    // boolean\nconst name = await ctx.ui.input(\"Name:\", \"placeholder\");                // string | undefined\nconst text = await ctx.ui.editor(\"Edit:\", \"prefilled text\");            // string | undefined\n\n// Timed auto-dismiss with countdown\nconst ok = await ctx.ui.confirm(\"Proceed?\", \"Auto-continues in 5s\", { timeout: 5000 });\n// Returns false on timeout, undefined for select/input\n\n// Manual dismissal with AbortSignal (distinguish timeout from cancel)\nconst controller = new AbortController();\nconst timeoutId = setTimeout(() => controller.abort(), 5000);\nconst ok = await ctx.ui.confirm(\"Timed\", \"Auto-cancels in 5s\", { signal: controller.signal });\nclearTimeout(timeoutId);\nif (controller.signal.aborted) { /* timed out */ }\n```\n</dialogs>\n\n<persistent_ui>\n```typescript\n// Footer status (multiple extensions can set independent entries)\nctx.ui.setStatus(\"my-ext\", \"● Active\");\nctx.ui.setStatus(\"my-ext\", undefined);  // Clear\n\n// Widgets\nctx.ui.setWidget(\"my-id\", [\"Line 1\", \"Line 2\"]);                       // Above editor\nctx.ui.setWidget(\"my-id\", [\"Below\"], { placement: \"belowEditor\" });    // Below editor\nctx.ui.setWidget(\"my-id\", (_tui, theme) => ({                          // Themed\n  render: () => [theme.fg(\"accent\", \"Styled\")],\n  invalidate: () => {},\n}));\nctx.ui.setWidget(\"my-id\", undefined);  // Clear\n\n// Working message during streaming\nctx.ui.setWorkingMessage(\"Analyzing code...\");\nctx.ui.setWorkingMessage();  // Restore default\n\n// Custom footer (full replacement)\nctx.ui.setFooter((tui, theme, footerData) => ({\n  render(width) {\n    const branch = footerData.getGitBranch();          // Only available here\n    const statuses = footerData.getExtensionStatuses(); // All setStatus values\n    return [truncateToWidth(`${branch} | model`, width)];\n  },\n  invalidate() {},\n  dispose: footerData.onBranchChange(() => tui.requestRender()),  // Reactive\n}));\nctx.ui.setFooter(undefined);  // Restore default\n\n// Custom header\nctx.ui.setHeader((tui, theme) => ({\n  render(width) { return [theme.fg(\"accent\", theme.bold(\"My Header\"))]; },\n  invalidate() {},\n}));\n\n// Editor control\nctx.ui.setEditorText(\"Prefill\");\nconst current = ctx.ui.getEditorText();\nctx.ui.pasteToEditor(\"pasted content\");  // Triggers paste handling\n\n// Tool expansion\nctx.ui.setToolsExpanded(true);\nconst expanded = ctx.ui.getToolsExpanded();\n\n// Theme management\nconst themes = ctx.ui.getAllThemes();\nctx.ui.setTheme(\"light\");\nctx.ui.theme.fg(\"accent\", \"text\");  // Access current theme\n```\n</persistent_ui>\n\n<custom_components>\n`ctx.ui.custom()` temporarily replaces the editor. Returns a value when `done()` is called.\n\n**Factory callback args:**\n\n| Argument | Type | Purpose |\n|----------|------|---------|\n| `tui` | `TUI` | `tui.requestRender()` triggers re-render after state changes |\n| `theme` | `Theme` | Current theme for styling |\n| `keybindings` | `KeybindingsManager` | App keybinding config |\n| `done` | `(value: T) => void` | Close component and return value |\n\n**Inline pattern:**\n```typescript\nconst result = await ctx.ui.custom<string | null>((tui, theme, keybindings, done) => ({\n  render(width: number): string[] {\n    return [truncateToWidth(\"Press Enter to confirm, Escape to cancel\", width)];\n  },\n  handleInput(data: string) {\n    if (matchesKey(data, Key.enter)) done(\"confirmed\");\n    if (matchesKey(data, Key.escape)) done(null);\n  },\n  invalidate() {},\n}));\n```\n\n**Class-based pattern (recommended for complex UI):**\n```typescript\nclass MyComponent {\n  private selected = 0;\n  private cachedWidth?: number;\n  private cachedLines?: string[];\n\n  constructor(\n    private tui: { requestRender: () => void },\n    private theme: Theme,\n    private items: string[],\n    private done: (value: string | null) => void,\n  ) {}\n\n  handleInput(data: string) {\n    if (matchesKey(data, Key.up) && this.selected > 0) this.selected--;\n    else if (matchesKey(data, Key.down) && this.selected < this.items.length - 1) this.selected++;\n    else if (matchesKey(data, Key.enter)) { this.done(this.items[this.selected]); return; }\n    else if (matchesKey(data, Key.escape)) { this.done(null); return; }\n    else return;\n    this.invalidate();\n    this.tui.requestRender();\n  }\n\n  render(width: number): string[] {\n    if (this.cachedLines && this.cachedWidth === width) return this.cachedLines;\n    this.cachedLines = this.items.map((item, i) =>\n      truncateToWidth((i === this.selected ? \"> \" : \"  \") + item, width)\n    );\n    this.cachedWidth = width;\n    return this.cachedLines;\n  }\n\n  invalidate() { this.cachedWidth = undefined; this.cachedLines = undefined; }\n}\n\nconst result = await ctx.ui.custom<string | null>((tui, theme, _kb, done) =>\n  new MyComponent(tui, theme, [\"A\", \"B\", \"C\"], done)\n);\n```\n\n**Composing with built-in components:**\n```typescript\nconst result = await ctx.ui.custom<string | null>((tui, theme, _kb, done) => {\n  const container = new Container();\n  container.addChild(new DynamicBorder((s: string) => theme.fg(\"accent\", s)));\n  container.addChild(new Text(theme.fg(\"accent\", theme.bold(\"Title\")), 1, 0));\n\n  const selectList = new SelectList(items, 10, {\n    selectedPrefix: (t) => theme.fg(\"accent\", t),\n    selectedText: (t) => theme.fg(\"accent\", t),\n    description: (t) => theme.fg(\"muted\", t),\n    scrollInfo: (t) => theme.fg(\"dim\", t),\n    noMatch: (t) => theme.fg(\"warning\", t),\n  });\n  selectList.onSelect = (item) => done(item.value);\n  selectList.onCancel = () => done(null);\n  container.addChild(selectList);\n\n  return {\n    render: (w) => container.render(w),\n    invalidate: () => container.invalidate(),\n    handleInput: (data) => { selectList.handleInput(data); tui.requestRender(); },\n  };\n});\n```\n</custom_components>\n\n<overlays>\nFloating modals rendered on top of everything:\n\n```typescript\nconst result = await ctx.ui.custom<string | null>(\n  (tui, theme, _kb, done) => new MyDialog({ onClose: done }),\n  {\n    overlay: true,\n    overlayOptions: {\n      anchor: \"center\",         // 9 positions (see below)\n      width: \"50%\",             // number = columns, string = percentage\n      minWidth: 40,\n      maxHeight: \"80%\",\n      margin: 2,                // All sides, or { top, right, bottom, left }\n      offsetX: 0, offsetY: 0,  // Fine-tune position\n      visible: (w, h) => w >= 80,  // Hide on narrow terminals\n    },\n    onHandle: (handle) => {\n      // handle.setHidden(true/false) — temporarily hide\n      // handle.hide() — permanently remove\n    },\n  }\n);\n```\n\n**Anchor positions:**\n```\ntop-left      top-center      top-right\nleft-center      center      right-center\nbottom-left  bottom-center  bottom-right\n```\n\n**Stacked overlays:** Multiple overlays stack (newest on top). Closing one gives focus to the one below.\n\n**⚠️ Overlay lifecycle:** Components are disposed when closed. Never reuse references — create fresh instances each time.\n</overlays>\n\n<custom_editor>\nReplace the main input editor permanently:\n\n```typescript\nimport { CustomEditor } from \"@gsd/pi-coding-agent\";\n\nclass VimEditor extends CustomEditor {\n  private mode: \"normal\" | \"insert\" = \"insert\";\n\n  handleInput(data: string): void {\n    if (matchesKey(data, \"escape\") && this.mode === \"insert\") {\n      this.mode = \"normal\"; return;\n    }\n    if (this.mode === \"insert\") { super.handleInput(data); return; }\n    switch (data) {\n      case \"i\": this.mode = \"insert\"; return;\n      case \"h\": super.handleInput(\"\\x1b[D\"); return;  // Left\n      case \"j\": super.handleInput(\"\\x1b[B\"); return;  // Down\n      case \"k\": super.handleInput(\"\\x1b[A\"); return;  // Up\n      case \"l\": super.handleInput(\"\\x1b[C\"); return;  // Right\n    }\n    if (data.length === 1 && data.charCodeAt(0) >= 32) return;  // Block printable in normal\n    super.handleInput(data);\n  }\n}\n\nctx.ui.setEditorComponent((_tui, theme, keybindings) => new VimEditor(theme, keybindings));\nctx.ui.setEditorComponent(undefined);  // Restore default\n```\n\n**Critical:** Extend `CustomEditor` (NOT `Editor`) to get app keybindings (escape to abort, ctrl+d, model switching).\n</custom_editor>\n\n<built_in_components>\n**From `@gsd/pi-tui`:**\n\n| Component | Constructor | Purpose |\n|-----------|-------------|---------|\n| `Text` | `new Text(content, paddingX, paddingY, bgFn?)` | Multi-line text with word wrap |\n| `Box` | `new Box(paddingX, paddingY, bgFn)` | Container with padding+background, `.addChild()` |\n| `Container` | `new Container()` | Vertical stack, `.addChild()`, `.removeChild()`, `.clear()` |\n| `Spacer` | `new Spacer(lines)` | Empty vertical space |\n| `Markdown` | `new Markdown(content, padX, padY, getMarkdownTheme())` | Rendered markdown with syntax highlighting |\n| `Image` | `new Image(base64, mimeType, theme, opts?)` | Image rendering (Kitty, iTerm2) |\n| `SelectList` | `new SelectList(items, maxVisible, themeOpts)` | Interactive selection with search and scrolling |\n| `SettingsList` | `new SettingsList(items, maxVisible, theme, onChange, onClose, opts?)` | Toggle settings with left/right arrows |\n| `Input` | `new Input()` | Text input field |\n| `Editor` | `new Editor(tui, editorTheme)` | Multi-line editor with undo |\n\n**SelectList usage:**\n```typescript\nconst items: SelectItem[] = [\n  { value: \"opt1\", label: \"Option 1\", description: \"First option\" },\n  { value: \"opt2\", label: \"Option 2\" },\n];\nconst selectList = new SelectList(items, 10, {\n  selectedPrefix: (t) => theme.fg(\"accent\", t),\n  selectedText: (t) => theme.fg(\"accent\", t),\n  description: (t) => theme.fg(\"muted\", t),\n  scrollInfo: (t) => theme.fg(\"dim\", t),\n  noMatch: (t) => theme.fg(\"warning\", t),\n});\nselectList.onSelect = (item) => { /* item.value */ };\nselectList.onCancel = () => { /* escape pressed */ };\n```\n\n**SettingsList usage:**\n```typescript\nconst items: SettingItem[] = [\n  { id: \"verbose\", label: \"Verbose mode\", currentValue: \"off\", values: [\"on\", \"off\"] },\n  { id: \"theme\", label: \"Theme\", currentValue: \"dark\", values: [\"dark\", \"light\", \"auto\"] },\n];\nconst settings = new SettingsList(items, 15, getSettingsListTheme(),\n  (id, newValue) => { /* setting changed */ },\n  () => { /* close requested */ },\n  { enableSearch: true },\n);\n```\n\n**From `@gsd/pi-coding-agent`:**\n\n| Component | Constructor | Purpose |\n|-----------|-------------|---------|\n| `DynamicBorder` | `new DynamicBorder((s: string) => theme.fg(\"accent\", s))` | Border line |\n| `BorderedLoader` | — | Spinner with cancel support |\n| `CustomEditor` | `new CustomEditor(theme, keybindings)` | Base class for custom editors |\n</built_in_components>\n\n<keyboard_input>\n```typescript\nimport { matchesKey, Key } from \"@gsd/pi-tui\";\n\nhandleInput(data: string) {\n  // Basic keys\n  if (matchesKey(data, Key.up)) {}\n  if (matchesKey(data, Key.down)) {}\n  if (matchesKey(data, Key.enter)) {}\n  if (matchesKey(data, Key.escape)) {}\n  if (matchesKey(data, Key.tab)) {}\n  if (matchesKey(data, Key.space)) {}\n  if (matchesKey(data, Key.backspace)) {}\n  if (matchesKey(data, Key.home)) {}\n  if (matchesKey(data, Key.end)) {}\n\n  // With modifiers\n  if (matchesKey(data, Key.ctrl(\"c\"))) {}\n  if (matchesKey(data, Key.shift(\"tab\"))) {}\n  if (matchesKey(data, Key.alt(\"left\"))) {}\n  if (matchesKey(data, Key.ctrlShift(\"p\"))) {}\n\n  // String format also works: \"enter\", \"ctrl+c\", \"shift+tab\"\n\n  // Printable character detection\n  if (data.length === 1 && data.charCodeAt(0) >= 32) {\n    // Letter, number, symbol\n  }\n}\n```\n\n**handleInput contract:**\n1. Check for your keys\n2. Update state\n3. Call `this.invalidate()` if render output changes\n4. Call `tui.requestRender()` to trigger re-render\n</keyboard_input>\n\n<line_width_rule>\n**Cardinal rule: each line from render() must not exceed `width` visible characters.**\n\n```typescript\nimport { visibleWidth, truncateToWidth, wrapTextWithAnsi } from \"@gsd/pi-tui\";\n\nvisibleWidth(\"\\x1b[32mHello\\x1b[0m\");  // Returns 5 (ignores ANSI codes)\ntruncateToWidth(\"Very long text here\", 10);         // \"Very lo...\"\ntruncateToWidth(\"Very long text here\", 10, \"\");      // \"Very long \" (no ellipsis)\nwrapTextWithAnsi(\"\\x1b[32mLong green text\\x1b[0m\", 10);  // Word wrap preserving ANSI\n```\n\nIf lines exceed `width`, terminal wraps cause visual corruption.\n</line_width_rule>\n\n<performance_caching>\nAlways cache render output:\n\n```typescript\nclass CachedComponent {\n  private cachedWidth?: number;\n  private cachedLines?: string[];\n\n  render(width: number): string[] {\n    if (this.cachedLines && this.cachedWidth === width) return this.cachedLines;\n    const lines = this.computeLines(width);\n    this.cachedWidth = width;\n    this.cachedLines = lines;\n    return lines;\n  }\n\n  invalidate() { this.cachedWidth = undefined; this.cachedLines = undefined; }\n}\n```\n\n**Update cycle:** State changes → `invalidate()` → `tui.requestRender()` → `render(width)` called\n\n**Game loop pattern** (real-time updates):\n```typescript\nthis.interval = setInterval(() => {\n  this.tick();\n  this.version++;\n  this.tui.requestRender();\n}, 100);  // 10 FPS\n\n// Clean up in dispose()\nclearInterval(this.interval);\n```\n</performance_caching>\n\n<theme_colors>\nAlways use theme from callback params, never import directly.\n\n**All foreground colors:**\n\n| Category | Colors |\n|----------|--------|\n| General | `text`, `accent`, `muted`, `dim` |\n| Status | `success`, `error`, `warning` |\n| Borders | `border`, `borderAccent`, `borderMuted` |\n| Messages | `userMessageText`, `customMessageText`, `customMessageLabel` |\n| Tools | `toolTitle`, `toolOutput` |\n| Diffs | `toolDiffAdded`, `toolDiffRemoved`, `toolDiffContext` |\n| Markdown | `mdHeading`, `mdLink`, `mdLinkUrl`, `mdCode`, `mdCodeBlock`, `mdCodeBlockBorder`, `mdQuote`, `mdQuoteBorder`, `mdHr`, `mdListBullet` |\n| Syntax | `syntaxComment`, `syntaxKeyword`, `syntaxFunction`, `syntaxVariable`, `syntaxString`, `syntaxNumber`, `syntaxType`, `syntaxOperator`, `syntaxPunctuation` |\n| Thinking | `thinkingOff`, `thinkingMinimal`, `thinkingLow`, `thinkingMedium`, `thinkingHigh`, `thinkingXhigh` |\n\n**All background colors:** `selectedBg`, `userMessageBg`, `customMessageBg`, `toolPendingBg`, `toolSuccessBg`, `toolErrorBg`\n\n**Syntax highlighting:**\n```typescript\nimport { highlightCode, getLanguageFromPath } from \"@gsd/pi-coding-agent\";\nconst lang = getLanguageFromPath(\"/file.rs\");  // \"rust\"\nconst highlighted = highlightCode(code, lang, theme);\n```\n</theme_colors>\n\n<common_mistakes>\n1. **Lines exceed width** → Visual corruption. Use `truncateToWidth()` on every line.\n2. **Forgetting `tui.requestRender()`** → UI doesn't update. Call after invalidate().\n3. **Importing theme directly** → Wrong colors after theme switch. Use theme from callback.\n4. **Not typing DynamicBorder param** → `new DynamicBorder((s: string) => theme.fg(\"accent\", s))`.\n5. **Reusing disposed overlay components** → Create fresh instances each time.\n6. **Styles bleeding across lines** → TUI resets per line. Reapply styles, or use `wrapTextWithAnsi()`.\n7. **Not implementing invalidate()** → Theme changes don't take effect.\n8. **Forgetting super.invalidate()** → `override invalidate() { super.invalidate(); /* cleanup */ }`\n9. **Timer not cleaned up** → Call `clearInterval` before `done()`.\n10. **Using ctx.ui in non-interactive mode** → Check `ctx.hasUI` first.\n</common_mistakes>\n","src/resources/skills/create-gsd-extension/references/events-reference.md":"<overview>\nComplete event reference with handler signatures, return types, and type narrowing utilities.\n</overview>\n\n<event_categories>\n\n**Session events:** `session_start`, `session_before_switch`, `session_switch`, `session_before_fork`, `session_fork`, `session_before_compact`, `session_compact`, `session_before_tree`, `session_tree`, `session_shutdown`\n\n**Agent events:** `before_agent_start`, `agent_start`, `agent_end`, `turn_start`, `turn_end`, `context`, `before_provider_request`, `message_start`, `message_update`, `message_end`\n\n**Tool events:** `tool_call`, `tool_execution_start`, `tool_execution_update`, `tool_execution_end`, `tool_result`\n\n**Input events:** `input`\n\n**Model events:** `model_select`\n\n**User bash events:** `user_bash`\n\n**Special:** `session_directory` (CLI startup only, no `ctx` — receives only event)\n\n</event_categories>\n\n<handler_signature>\n```typescript\npi.on(\"event_name\", async (event, ctx: ExtensionContext) => {\n  // event — typed payload for this event\n  // ctx — access to UI, session, model, control flow\n  // Return undefined for no action, or a typed response\n});\n```\n</handler_signature>\n\n<key_events>\n\n**before_agent_start** — Fired after user prompt, before agent loop. Primary hook for context injection and system prompt modification.\n```typescript\npi.on(\"before_agent_start\", async (event, ctx) => {\n  // event.prompt — user's prompt text\n  // event.images — attached images\n  // event.systemPrompt — current system prompt\n  return {\n    message: { customType: \"my-ext\", content: \"Extra context\", display: true },\n    systemPrompt: event.systemPrompt + \"\\n\\nExtra instructions...\",\n  };\n});\n```\n\n**tool_call** — Fired before tool executes. Can block.\n```typescript\nimport { isToolCallEventType } from \"@gsd/pi-coding-agent\";\n\npi.on(\"tool_call\", async (event, ctx) => {\n  if (isToolCallEventType(\"bash\", event)) {\n    // event.input is typed as { command: string; timeout?: number }\n    if (event.input.command.includes(\"rm -rf\")) {\n      return { block: true, reason: \"Dangerous command\" };\n    }\n  }\n});\n```\n\n**tool_result** — Fired after tool executes. Can modify result. Handlers chain like middleware.\n```typescript\nimport { isToolResultEventType } from \"@gsd/pi-coding-agent\";\n\npi.on(\"tool_result\", async (event, ctx) => {\n  if (isToolResultEventType(\"bash\", event)) {\n    // event.details is typed as BashToolDetails\n  }\n  // Return partial patch: { content, details, isError }\n  // Omitted fields keep current values\n});\n```\n\n**context** — Fired before each LLM call. Modify messages non-destructively.\n```typescript\npi.on(\"context\", async (event, ctx) => {\n  // event.messages is a deep copy — safe to modify\n  const filtered = event.messages.filter(m => !shouldPrune(m));\n  return { messages: filtered };\n});\n```\n\n**input** — Fired when user input is received, before skill/template expansion.\n```typescript\npi.on(\"input\", async (event, ctx) => {\n  // event.text — raw input\n  // event.source — \"interactive\", \"rpc\", or \"extension\"\n  if (event.text.startsWith(\"?quick \"))\n    return { action: \"transform\", text: `Respond briefly: ${event.text.slice(7)}` };\n  return { action: \"continue\" };\n});\n```\n\n**model_select** — Fired when model changes.\n```typescript\npi.on(\"model_select\", async (event, ctx) => {\n  // event.model, event.previousModel, event.source (\"set\"|\"cycle\"|\"restore\")\n});\n```\n\n</key_events>\n\n<type_narrowing>\nBuilt-in type guards for tool events:\n\n```typescript\nimport { isToolCallEventType, isToolResultEventType } from \"@gsd/pi-coding-agent\";\n\n// Tool calls — narrows event.input type\nif (isToolCallEventType(\"bash\", event)) { /* event.input: { command, timeout? } */ }\nif (isToolCallEventType(\"read\", event)) { /* event.input: { path, offset?, limit? } */ }\nif (isToolCallEventType(\"write\", event)) { /* event.input: { path, content } */ }\nif (isToolCallEventType(\"edit\", event)) { /* event.input: { path, oldText, newText } */ }\n\n// Tool results — narrows event.details type\nif (isToolResultEventType(\"bash\", event)) { /* event.details: BashToolDetails */ }\n```\n\nFor custom tools, export your input type and use explicit type params:\n```typescript\nif (isToolCallEventType<\"my_tool\", MyToolInput>(\"my_tool\", event)) {\n  event.input.action; // typed\n}\n```\n</type_narrowing>\n","src/resources/skills/create-gsd-extension/references/extension-lifecycle.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fextension-lifecycle.md -->","src/resources/skills/create-gsd-extension/references/extensionapi-reference.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fextensionapi-reference.md -->","src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fextensioncontext-reference.md -->","src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fkey-rules-gotchas.md -->","src/resources/skills/create-gsd-extension/references/mode-behavior.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fmode-behavior.md -->","src/resources/skills/create-gsd-extension/references/model-provider-management.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fmodel-provider-management.md -->","src/resources/skills/create-gsd-extension/references/packaging-distribution.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fpackaging-distribution.md -->","src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fremote-execution-overrides.md -->","src/resources/skills/create-gsd-extension/references/state-management.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fstate-management.md -->","src/resources/skills/create-gsd-extension/references/system-prompt-modification.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fsystem-prompt-modification.md -->","src/resources/skills/create-gsd-extension/workflows/add-capability.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Fworkflows%2Fadd-capability.md -->","src/resources/skills/create-gsd-extension/workflows/create-extension.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Fworkflows%2Fcreate-extension.md -->","src/resources/skills/create-gsd-extension/workflows/debug-extension.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Fworkflows%2Fdebug-extension.md -->","src/resources/skills/create-mcp-server/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-mcp-server%2FSKILL.md -->","src/resources/skills/create-skill/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2FSKILL.md -->","src/resources/skills/create-skill/references/api-security.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fapi-security.md -->","src/resources/skills/create-skill/references/be-clear-and-direct.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fbe-clear-and-direct.md -->","src/resources/skills/create-skill/references/common-patterns.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fcommon-patterns.md -->","src/resources/skills/create-skill/references/core-principles.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fcore-principles.md -->","src/resources/skills/create-skill/references/executable-code.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fexecutable-code.md -->","src/resources/skills/create-skill/references/gsd-skill-ecosystem.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fgsd-skill-ecosystem.md -->","src/resources/skills/create-skill/references/iteration-and-testing.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fiteration-and-testing.md -->","src/resources/skills/create-skill/references/recommended-structure.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Frecommended-structure.md -->","src/resources/skills/create-skill/references/skill-structure.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fskill-structure.md -->","src/resources/skills/create-skill/references/use-xml-tags.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fuse-xml-tags.md -->","src/resources/skills/create-skill/references/using-scripts.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fusing-scripts.md -->","src/resources/skills/create-skill/references/using-templates.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fusing-templates.md -->","src/resources/skills/create-skill/references/workflows-and-validation.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fworkflows-and-validation.md -->","src/resources/skills/create-skill/templates/router-skill.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Ftemplates%2Frouter-skill.md -->","src/resources/skills/create-skill/templates/simple-skill.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Ftemplates%2Fsimple-skill.md -->","src/resources/skills/create-skill/workflows/add-reference.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fadd-reference.md -->","src/resources/skills/create-skill/workflows/add-script.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fadd-script.md -->","src/resources/skills/create-skill/workflows/add-template.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fadd-template.md -->","src/resources/skills/create-skill/workflows/add-workflow.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fadd-workflow.md -->","src/resources/skills/create-skill/workflows/audit-skill.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Faudit-skill.md -->","src/resources/skills/create-skill/workflows/create-new-skill.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fcreate-new-skill.md -->","src/resources/skills/create-skill/workflows/get-guidance.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fget-guidance.md -->","src/resources/skills/create-skill/workflows/upgrade-to-router.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fupgrade-to-router.md -->","src/resources/skills/create-skill/workflows/verify-skill.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fverify-skill.md -->","src/resources/skills/create-workflow/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2FSKILL.md -->","src/resources/skills/create-workflow/references/feature-patterns.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Freferences%2Ffeature-patterns.md -->","src/resources/skills/create-workflow/references/verification-policies.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Freferences%2Fverification-policies.md -->","src/resources/skills/create-workflow/references/yaml-schema-v1.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Freferences%2Fyaml-schema-v1.md -->","src/resources/skills/create-workflow/templates/blog-post-pipeline.yaml":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Ftemplates%2Fblog-post-pipeline.yaml -->","src/resources/skills/create-workflow/templates/code-audit.yaml":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Ftemplates%2Fcode-audit.yaml -->","src/resources/skills/create-workflow/templates/release-checklist.yaml":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Ftemplates%2Frelease-checklist.yaml -->","src/resources/skills/create-workflow/templates/workflow-definition.yaml":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Ftemplates%2Fworkflow-definition.yaml -->","src/resources/skills/create-workflow/workflows/create-from-scratch.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Fworkflows%2Fcreate-from-scratch.md -->","src/resources/skills/create-workflow/workflows/create-from-template.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Fworkflows%2Fcreate-from-template.md -->","src/resources/skills/debug-like-expert/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2FSKILL.md -->","src/resources/skills/debug-like-expert/references/debugging-mindset.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2Freferences%2Fdebugging-mindset.md -->","src/resources/skills/debug-like-expert/references/hypothesis-testing.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2Freferences%2Fhypothesis-testing.md -->","src/resources/skills/debug-like-expert/references/investigation-techniques.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2Freferences%2Finvestigation-techniques.md -->","src/resources/skills/debug-like-expert/references/verification-patterns.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2Freferences%2Fverification-patterns.md -->","src/resources/skills/debug-like-expert/references/when-to-research.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2Freferences%2Fwhen-to-research.md -->","src/resources/skills/decompose-into-slices/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdecompose-into-slices%2FSKILL.md -->","src/resources/skills/dependency-upgrade/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdependency-upgrade%2FSKILL.md -->","src/resources/skills/design-an-interface/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdesign-an-interface%2FSKILL.md -->","src/resources/skills/forensics/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fforensics%2FSKILL.md -->","src/resources/skills/frontend-design/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Ffrontend-design%2FSKILL.md -->","src/resources/skills/github-workflows/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2FSKILL.md -->","src/resources/skills/github-workflows/references/gh/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2Freferences%2Fgh%2FSKILL.md -->","src/resources/skills/github-workflows/references/gh/references/issue-stories.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2Freferences%2Fgh%2Freferences%2Fissue-stories.md -->","src/resources/skills/github-workflows/references/gh/references/labels.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2Freferences%2Fgh%2Freferences%2Flabels.md -->","src/resources/skills/github-workflows/references/gh/references/milestones.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2Freferences%2Fgh%2Freferences%2Fmilestones.md -->","src/resources/skills/github-workflows/references/gh/references/projects-v2.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2Freferences%2Fgh%2Freferences%2Fprojects-v2.md -->","src/resources/skills/grill-me/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgrill-me%2FSKILL.md -->","src/resources/skills/handoff/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fhandoff%2FSKILL.md -->","src/resources/skills/lint/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Flint%2FSKILL.md -->","src/resources/skills/make-interfaces-feel-better/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fmake-interfaces-feel-better%2FSKILL.md -->","src/resources/skills/make-interfaces-feel-better/animations.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fmake-interfaces-feel-better%2Fanimations.md -->","src/resources/skills/make-interfaces-feel-better/performance.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fmake-interfaces-feel-better%2Fperformance.md -->","src/resources/skills/make-interfaces-feel-better/surfaces.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fmake-interfaces-feel-better%2Fsurfaces.md -->","src/resources/skills/make-interfaces-feel-better/typography.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fmake-interfaces-feel-better%2Ftypography.md -->","src/resources/skills/observability/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fobservability%2FSKILL.md -->","src/resources/skills/react-best-practices/README.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2FREADME.md -->","src/resources/skills/react-best-practices/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2FSKILL.md -->","src/resources/skills/react-best-practices/metadata.json":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Fmetadata.json -->","src/resources/skills/react-best-practices/rules/_sections.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2F_sections.md -->","src/resources/skills/react-best-practices/rules/_template.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2F_template.md -->","src/resources/skills/react-best-practices/rules/advanced-event-handler-refs.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fadvanced-event-handler-refs.md -->","src/resources/skills/react-best-practices/rules/advanced-init-once.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fadvanced-init-once.md -->","src/resources/skills/react-best-practices/rules/advanced-use-latest.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fadvanced-use-latest.md -->","src/resources/skills/react-best-practices/rules/async-api-routes.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fasync-api-routes.md -->","src/resources/skills/react-best-practices/rules/async-defer-await.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fasync-defer-await.md -->","src/resources/skills/react-best-practices/rules/async-dependencies.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fasync-dependencies.md -->","src/resources/skills/react-best-practices/rules/async-parallel.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fasync-parallel.md -->","src/resources/skills/react-best-practices/rules/async-suspense-boundaries.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fasync-suspense-boundaries.md -->","src/resources/skills/react-best-practices/rules/bundle-barrel-imports.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fbundle-barrel-imports.md -->","src/resources/skills/react-best-practices/rules/bundle-conditional.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fbundle-conditional.md -->","src/resources/skills/react-best-practices/rules/bundle-defer-third-party.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fbundle-defer-third-party.md -->","src/resources/skills/react-best-practices/rules/bundle-dynamic-imports.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fbundle-dynamic-imports.md -->","src/resources/skills/react-best-practices/rules/bundle-preload.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fbundle-preload.md -->","src/resources/skills/react-best-practices/rules/client-event-listeners.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fclient-event-listeners.md -->","src/resources/skills/react-best-practices/rules/client-localstorage-schema.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fclient-localstorage-schema.md -->","src/resources/skills/react-best-practices/rules/client-passive-event-listeners.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fclient-passive-event-listeners.md -->","src/resources/skills/react-best-practices/rules/client-swr-dedup.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fclient-swr-dedup.md -->","src/resources/skills/react-best-practices/rules/js-batch-dom-css.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-batch-dom-css.md -->","src/resources/skills/react-best-practices/rules/js-cache-function-results.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-cache-function-results.md -->","src/resources/skills/react-best-practices/rules/js-cache-property-access.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-cache-property-access.md -->","src/resources/skills/react-best-practices/rules/js-cache-storage.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-cache-storage.md -->","src/resources/skills/react-best-practices/rules/js-combine-iterations.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-combine-iterations.md -->","src/resources/skills/react-best-practices/rules/js-early-exit.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-early-exit.md -->","src/resources/skills/react-best-practices/rules/js-hoist-regexp.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-hoist-regexp.md -->","src/resources/skills/react-best-practices/rules/js-index-maps.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-index-maps.md -->","src/resources/skills/react-best-practices/rules/js-length-check-first.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-length-check-first.md -->","src/resources/skills/react-best-practices/rules/js-min-max-loop.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-min-max-loop.md -->","src/resources/skills/react-best-practices/rules/js-set-map-lookups.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-set-map-lookups.md -->","src/resources/skills/react-best-practices/rules/js-tosorted-immutable.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-tosorted-immutable.md -->","src/resources/skills/react-best-practices/rules/rendering-activity.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-activity.md -->","src/resources/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-animate-svg-wrapper.md -->","src/resources/skills/react-best-practices/rules/rendering-conditional-render.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-conditional-render.md -->","src/resources/skills/react-best-practices/rules/rendering-content-visibility.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-content-visibility.md -->","src/resources/skills/react-best-practices/rules/rendering-hoist-jsx.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-hoist-jsx.md -->","src/resources/skills/react-best-practices/rules/rendering-hydration-no-flicker.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-hydration-no-flicker.md -->","src/resources/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-hydration-suppress-warning.md -->","src/resources/skills/react-best-practices/rules/rendering-svg-precision.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-svg-precision.md -->","src/resources/skills/react-best-practices/rules/rendering-usetransition-loading.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-usetransition-loading.md -->","src/resources/skills/react-best-practices/rules/rerender-defer-reads.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-defer-reads.md -->","src/resources/skills/react-best-practices/rules/rerender-dependencies.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-dependencies.md -->","src/resources/skills/react-best-practices/rules/rerender-derived-state-no-effect.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-derived-state-no-effect.md -->","src/resources/skills/react-best-practices/rules/rerender-derived-state.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-derived-state.md -->","src/resources/skills/react-best-practices/rules/rerender-functional-setstate.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-functional-setstate.md -->","src/resources/skills/react-best-practices/rules/rerender-lazy-state-init.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-lazy-state-init.md -->","src/resources/skills/react-best-practices/rules/rerender-memo-with-default-value.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-memo-with-default-value.md -->","src/resources/skills/react-best-practices/rules/rerender-memo.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-memo.md -->","src/resources/skills/react-best-practices/rules/rerender-move-effect-to-event.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-move-effect-to-event.md -->","src/resources/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-simple-expression-in-memo.md -->","src/resources/skills/react-best-practices/rules/rerender-transitions.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-transitions.md -->","src/resources/skills/react-best-practices/rules/rerender-use-ref-transient-values.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-use-ref-transient-values.md -->","src/resources/skills/react-best-practices/rules/server-after-nonblocking.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-after-nonblocking.md -->","src/resources/skills/react-best-practices/rules/server-auth-actions.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-auth-actions.md -->","src/resources/skills/react-best-practices/rules/server-cache-lru.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-cache-lru.md -->","src/resources/skills/react-best-practices/rules/server-cache-react.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-cache-react.md -->","src/resources/skills/react-best-practices/rules/server-dedup-props.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-dedup-props.md -->","src/resources/skills/react-best-practices/rules/server-parallel-fetching.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-parallel-fetching.md -->","src/resources/skills/react-best-practices/rules/server-serialization.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-serialization.md -->","src/resources/skills/review/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freview%2FSKILL.md -->","src/resources/skills/security-review/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fsecurity-review%2FSKILL.md -->","src/resources/skills/spike-wrap-up/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fspike-wrap-up%2FSKILL.md -->","src/resources/skills/tdd/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Ftdd%2FSKILL.md -->","src/resources/skills/test/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Ftest%2FSKILL.md -->","src/resources/skills/userinterface-wiki/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2FSKILL.md -->","src/resources/skills/userinterface-wiki/rules/_sections.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2F_sections.md -->","src/resources/skills/userinterface-wiki/rules/_template.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2F_template.md -->","src/resources/skills/userinterface-wiki/rules/a11y-reduced-motion-check.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fa11y-reduced-motion-check.md -->","src/resources/skills/userinterface-wiki/rules/a11y-toggle-setting.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fa11y-toggle-setting.md -->","src/resources/skills/userinterface-wiki/rules/a11y-visual-equivalent.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fa11y-visual-equivalent.md -->","src/resources/skills/userinterface-wiki/rules/a11y-volume-control.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fa11y-volume-control.md -->","src/resources/skills/userinterface-wiki/rules/appropriate-confirmations-only.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fappropriate-confirmations-only.md -->","src/resources/skills/userinterface-wiki/rules/appropriate-errors-warnings.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fappropriate-errors-warnings.md -->","src/resources/skills/userinterface-wiki/rules/appropriate-no-decorative.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fappropriate-no-decorative.md -->","src/resources/skills/userinterface-wiki/rules/appropriate-no-high-frequency.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fappropriate-no-high-frequency.md -->","src/resources/skills/userinterface-wiki/rules/appropriate-no-punishing.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fappropriate-no-punishing.md -->","src/resources/skills/userinterface-wiki/rules/container-callback-ref.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-callback-ref.md -->","src/resources/skills/userinterface-wiki/rules/container-guard-initial-zero.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-guard-initial-zero.md -->","src/resources/skills/userinterface-wiki/rules/container-no-excessive-use.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-no-excessive-use.md -->","src/resources/skills/userinterface-wiki/rules/container-overflow-hidden.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-overflow-hidden.md -->","src/resources/skills/userinterface-wiki/rules/container-transition-delay.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-transition-delay.md -->","src/resources/skills/userinterface-wiki/rules/container-two-div-pattern.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-two-div-pattern.md -->","src/resources/skills/userinterface-wiki/rules/container-use-resize-observer.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-use-resize-observer.md -->","src/resources/skills/userinterface-wiki/rules/context-cleanup-nodes.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontext-cleanup-nodes.md -->","src/resources/skills/userinterface-wiki/rules/context-resume-suspended.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontext-resume-suspended.md -->","src/resources/skills/userinterface-wiki/rules/context-reuse-single.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontext-reuse-single.md -->","src/resources/skills/userinterface-wiki/rules/design-filter-for-character.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fdesign-filter-for-character.md -->","src/resources/skills/userinterface-wiki/rules/design-noise-for-percussion.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fdesign-noise-for-percussion.md -->","src/resources/skills/userinterface-wiki/rules/design-oscillator-for-tonal.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fdesign-oscillator-for-tonal.md -->","src/resources/skills/userinterface-wiki/rules/duration-max-300ms.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fduration-max-300ms.md -->","src/resources/skills/userinterface-wiki/rules/duration-press-hover.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fduration-press-hover.md -->","src/resources/skills/userinterface-wiki/rules/duration-shorten-before-curve.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fduration-shorten-before-curve.md -->","src/resources/skills/userinterface-wiki/rules/duration-small-state.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fduration-small-state.md -->","src/resources/skills/userinterface-wiki/rules/easing-entrance-ease-out.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-entrance-ease-out.md -->","src/resources/skills/userinterface-wiki/rules/easing-exit-ease-in.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-exit-ease-in.md -->","src/resources/skills/userinterface-wiki/rules/easing-for-state-change.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-for-state-change.md -->","src/resources/skills/userinterface-wiki/rules/easing-linear-only-progress.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-linear-only-progress.md -->","src/resources/skills/userinterface-wiki/rules/easing-natural-decay.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-natural-decay.md -->","src/resources/skills/userinterface-wiki/rules/easing-no-linear-motion.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-no-linear-motion.md -->","src/resources/skills/userinterface-wiki/rules/easing-transition-ease-in-out.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-transition-ease-in-out.md -->","src/resources/skills/userinterface-wiki/rules/envelope-exponential-decay.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fenvelope-exponential-decay.md -->","src/resources/skills/userinterface-wiki/rules/envelope-no-zero-target.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fenvelope-no-zero-target.md -->","src/resources/skills/userinterface-wiki/rules/envelope-set-initial-value.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fenvelope-set-initial-value.md -->","src/resources/skills/userinterface-wiki/rules/exit-key-required.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fexit-key-required.md -->","src/resources/skills/userinterface-wiki/rules/exit-matches-initial.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fexit-matches-initial.md -->","src/resources/skills/userinterface-wiki/rules/exit-prop-required.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fexit-prop-required.md -->","src/resources/skills/userinterface-wiki/rules/exit-requires-wrapper.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fexit-requires-wrapper.md -->","src/resources/skills/userinterface-wiki/rules/impl-default-subtle.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fimpl-default-subtle.md -->","src/resources/skills/userinterface-wiki/rules/impl-preload-audio.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fimpl-preload-audio.md -->","src/resources/skills/userinterface-wiki/rules/impl-reset-current-time.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fimpl-reset-current-time.md -->","src/resources/skills/userinterface-wiki/rules/mode-pop-layout-for-lists.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmode-pop-layout-for-lists.md -->","src/resources/skills/userinterface-wiki/rules/mode-sync-layout-conflict.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmode-sync-layout-conflict.md -->","src/resources/skills/userinterface-wiki/rules/mode-wait-doubles-duration.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmode-wait-doubles-duration.md -->","src/resources/skills/userinterface-wiki/rules/morphing-aria-hidden.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-aria-hidden.md -->","src/resources/skills/userinterface-wiki/rules/morphing-consistent-viewbox.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-consistent-viewbox.md -->","src/resources/skills/userinterface-wiki/rules/morphing-group-variants.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-group-variants.md -->","src/resources/skills/userinterface-wiki/rules/morphing-jump-non-grouped.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-jump-non-grouped.md -->","src/resources/skills/userinterface-wiki/rules/morphing-reduced-motion.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-reduced-motion.md -->","src/resources/skills/userinterface-wiki/rules/morphing-spring-rotation.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-spring-rotation.md -->","src/resources/skills/userinterface-wiki/rules/morphing-strokelinecap-round.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-strokelinecap-round.md -->","src/resources/skills/userinterface-wiki/rules/morphing-three-lines.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-three-lines.md -->","src/resources/skills/userinterface-wiki/rules/morphing-use-collapsed.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-use-collapsed.md -->","src/resources/skills/userinterface-wiki/rules/native-backdrop-styling.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnative-backdrop-styling.md -->","src/resources/skills/userinterface-wiki/rules/native-placeholder-styling.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnative-placeholder-styling.md -->","src/resources/skills/userinterface-wiki/rules/native-selection-styling.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnative-selection-styling.md -->","src/resources/skills/userinterface-wiki/rules/nested-consistent-timing.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnested-consistent-timing.md -->","src/resources/skills/userinterface-wiki/rules/nested-propagate-required.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnested-propagate-required.md -->","src/resources/skills/userinterface-wiki/rules/none-context-menu-entrance.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnone-context-menu-entrance.md -->","src/resources/skills/userinterface-wiki/rules/none-high-frequency.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnone-high-frequency.md -->","src/resources/skills/userinterface-wiki/rules/none-keyboard-navigation.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnone-keyboard-navigation.md -->","src/resources/skills/userinterface-wiki/rules/param-click-duration.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fparam-click-duration.md -->","src/resources/skills/userinterface-wiki/rules/param-filter-frequency-range.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fparam-filter-frequency-range.md -->","src/resources/skills/userinterface-wiki/rules/param-q-value-range.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fparam-q-value-range.md -->","src/resources/skills/userinterface-wiki/rules/param-reasonable-gain.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fparam-reasonable-gain.md -->","src/resources/skills/userinterface-wiki/rules/physics-active-state.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fphysics-active-state.md -->","src/resources/skills/userinterface-wiki/rules/physics-no-excessive-stagger.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fphysics-no-excessive-stagger.md -->","src/resources/skills/userinterface-wiki/rules/physics-spring-for-overshoot.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fphysics-spring-for-overshoot.md -->","src/resources/skills/userinterface-wiki/rules/physics-subtle-deformation.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fphysics-subtle-deformation.md -->","src/resources/skills/userinterface-wiki/rules/prefetch-hit-slop.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-hit-slop.md -->","src/resources/skills/userinterface-wiki/rules/prefetch-keyboard-tab.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-keyboard-tab.md -->","src/resources/skills/userinterface-wiki/rules/prefetch-not-everything.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-not-everything.md -->","src/resources/skills/userinterface-wiki/rules/prefetch-touch-fallback.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-touch-fallback.md -->","src/resources/skills/userinterface-wiki/rules/prefetch-trajectory-over-hover.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-trajectory-over-hover.md -->","src/resources/skills/userinterface-wiki/rules/prefetch-use-selectively.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-use-selectively.md -->","src/resources/skills/userinterface-wiki/rules/presence-disable-interactions.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpresence-disable-interactions.md -->","src/resources/skills/userinterface-wiki/rules/presence-hook-in-child.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpresence-hook-in-child.md -->","src/resources/skills/userinterface-wiki/rules/presence-safe-to-remove.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpresence-safe-to-remove.md -->","src/resources/skills/userinterface-wiki/rules/pseudo-content-required.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-content-required.md -->","src/resources/skills/userinterface-wiki/rules/pseudo-first-line-styling.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-first-line-styling.md -->","src/resources/skills/userinterface-wiki/rules/pseudo-hit-target-expansion.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-hit-target-expansion.md -->","src/resources/skills/userinterface-wiki/rules/pseudo-marker-styling.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-marker-styling.md -->","src/resources/skills/userinterface-wiki/rules/pseudo-over-dom-node.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-over-dom-node.md -->","src/resources/skills/userinterface-wiki/rules/pseudo-position-relative-parent.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-position-relative-parent.md -->","src/resources/skills/userinterface-wiki/rules/pseudo-z-index-layering.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-z-index-layering.md -->","src/resources/skills/userinterface-wiki/rules/spring-for-gestures.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fspring-for-gestures.md -->","src/resources/skills/userinterface-wiki/rules/spring-for-interruptible.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fspring-for-interruptible.md -->","src/resources/skills/userinterface-wiki/rules/spring-params-balanced.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fspring-params-balanced.md -->","src/resources/skills/userinterface-wiki/rules/spring-preserves-velocity.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fspring-preserves-velocity.md -->","src/resources/skills/userinterface-wiki/rules/staging-dim-background.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fstaging-dim-background.md -->","src/resources/skills/userinterface-wiki/rules/staging-one-focal-point.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fstaging-one-focal-point.md -->","src/resources/skills/userinterface-wiki/rules/staging-z-index-hierarchy.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fstaging-z-index-hierarchy.md -->","src/resources/skills/userinterface-wiki/rules/timing-consistent.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftiming-consistent.md -->","src/resources/skills/userinterface-wiki/rules/timing-no-entrance-context-menu.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftiming-no-entrance-context-menu.md -->","src/resources/skills/userinterface-wiki/rules/timing-under-300ms.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftiming-under-300ms.md -->","src/resources/skills/userinterface-wiki/rules/transition-name-cleanup.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftransition-name-cleanup.md -->","src/resources/skills/userinterface-wiki/rules/transition-name-required.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftransition-name-required.md -->","src/resources/skills/userinterface-wiki/rules/transition-name-unique.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftransition-name-unique.md -->","src/resources/skills/userinterface-wiki/rules/transition-over-js-library.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftransition-over-js-library.md -->","src/resources/skills/userinterface-wiki/rules/transition-style-pseudo-elements.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftransition-style-pseudo-elements.md -->","src/resources/skills/userinterface-wiki/rules/type-antialiased-on-retina.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-antialiased-on-retina.md -->","src/resources/skills/userinterface-wiki/rules/type-disambiguation-stylistic-set.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-disambiguation-stylistic-set.md -->","src/resources/skills/userinterface-wiki/rules/type-font-display-swap.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-font-display-swap.md -->","src/resources/skills/userinterface-wiki/rules/type-justify-with-hyphens.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-justify-with-hyphens.md -->","src/resources/skills/userinterface-wiki/rules/type-letter-spacing-uppercase.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-letter-spacing-uppercase.md -->","src/resources/skills/userinterface-wiki/rules/type-no-font-synthesis.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-no-font-synthesis.md -->","src/resources/skills/userinterface-wiki/rules/type-oldstyle-nums-for-prose.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-oldstyle-nums-for-prose.md -->","src/resources/skills/userinterface-wiki/rules/type-opentype-contextual-alternates.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-opentype-contextual-alternates.md -->","src/resources/skills/userinterface-wiki/rules/type-optical-sizing-auto.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-optical-sizing-auto.md -->","src/resources/skills/userinterface-wiki/rules/type-proper-fractions.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-proper-fractions.md -->","src/resources/skills/userinterface-wiki/rules/type-slashed-zero.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-slashed-zero.md -->","src/resources/skills/userinterface-wiki/rules/type-tabular-nums-for-data.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-tabular-nums-for-data.md -->","src/resources/skills/userinterface-wiki/rules/type-text-wrap-balance-headings.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-text-wrap-balance-headings.md -->","src/resources/skills/userinterface-wiki/rules/type-text-wrap-pretty.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-text-wrap-pretty.md -->","src/resources/skills/userinterface-wiki/rules/type-underline-offset.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-underline-offset.md -->","src/resources/skills/userinterface-wiki/rules/type-variable-weight-continuous.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-variable-weight-continuous.md -->","src/resources/skills/userinterface-wiki/rules/ux-aesthetic-usability.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-aesthetic-usability.md -->","src/resources/skills/userinterface-wiki/rules/ux-cognitive-load-reduce.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-cognitive-load-reduce.md -->","src/resources/skills/userinterface-wiki/rules/ux-common-region-boundaries.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-common-region-boundaries.md -->","src/resources/skills/userinterface-wiki/rules/ux-doherty-perceived-speed.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-doherty-perceived-speed.md -->","src/resources/skills/userinterface-wiki/rules/ux-doherty-under-400ms.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-doherty-under-400ms.md -->","src/resources/skills/userinterface-wiki/rules/ux-fitts-hit-area.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-fitts-hit-area.md -->","src/resources/skills/userinterface-wiki/rules/ux-fitts-target-size.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-fitts-target-size.md -->","src/resources/skills/userinterface-wiki/rules/ux-goal-gradient-progress.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-goal-gradient-progress.md -->","src/resources/skills/userinterface-wiki/rules/ux-hicks-minimize-choices.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-hicks-minimize-choices.md -->","src/resources/skills/userinterface-wiki/rules/ux-jakobs-familiar-patterns.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-jakobs-familiar-patterns.md -->","src/resources/skills/userinterface-wiki/rules/ux-millers-chunking.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-millers-chunking.md -->","src/resources/skills/userinterface-wiki/rules/ux-pareto-prioritize-features.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-pareto-prioritize-features.md -->","src/resources/skills/userinterface-wiki/rules/ux-peak-end-finish-strong.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-peak-end-finish-strong.md -->","src/resources/skills/userinterface-wiki/rules/ux-postels-accept-messy-input.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-postels-accept-messy-input.md -->","src/resources/skills/userinterface-wiki/rules/ux-pragnanz-simplify.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-pragnanz-simplify.md -->","src/resources/skills/userinterface-wiki/rules/ux-progressive-disclosure.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-progressive-disclosure.md -->","src/resources/skills/userinterface-wiki/rules/ux-proximity-grouping.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-proximity-grouping.md -->","src/resources/skills/userinterface-wiki/rules/ux-serial-position.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-serial-position.md -->","src/resources/skills/userinterface-wiki/rules/ux-similarity-consistency.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-similarity-consistency.md -->","src/resources/skills/userinterface-wiki/rules/ux-teslers-complexity.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-teslers-complexity.md -->","src/resources/skills/userinterface-wiki/rules/ux-uniform-connectedness.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-uniform-connectedness.md -->","src/resources/skills/userinterface-wiki/rules/ux-von-restorff-emphasis.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-von-restorff-emphasis.md -->","src/resources/skills/userinterface-wiki/rules/ux-zeigarnik-show-incomplete.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-zeigarnik-show-incomplete.md -->","src/resources/skills/userinterface-wiki/rules/visual-animate-shadow-pseudo.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-animate-shadow-pseudo.md -->","src/resources/skills/userinterface-wiki/rules/visual-border-alpha-colors.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-border-alpha-colors.md -->","src/resources/skills/userinterface-wiki/rules/visual-button-shadow-anatomy.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-button-shadow-anatomy.md -->","src/resources/skills/userinterface-wiki/rules/visual-concentric-radius.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-concentric-radius.md -->","src/resources/skills/userinterface-wiki/rules/visual-consistent-spacing-scale.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-consistent-spacing-scale.md -->","src/resources/skills/userinterface-wiki/rules/visual-layered-shadows.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-layered-shadows.md -->","src/resources/skills/userinterface-wiki/rules/visual-no-pure-black-shadow.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-no-pure-black-shadow.md -->","src/resources/skills/userinterface-wiki/rules/visual-shadow-direction.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-shadow-direction.md -->","src/resources/skills/userinterface-wiki/rules/visual-shadow-matches-elevation.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-shadow-matches-elevation.md -->","src/resources/skills/userinterface-wiki/rules/weight-duration-matches-action.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fweight-duration-matches-action.md -->","src/resources/skills/userinterface-wiki/rules/weight-match-action.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fweight-match-action.md -->","src/resources/skills/verify-before-complete/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fverify-before-complete%2FSKILL.md -->","src/resources/skills/web-design-guidelines/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fweb-design-guidelines%2FSKILL.md -->","src/resources/skills/web-quality-audit/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fweb-quality-audit%2FSKILL.md -->","src/resources/skills/write-docs/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fwrite-docs%2FSKILL.md -->","src/resources/skills/write-milestone-brief/SKILL.md":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fwrite-milestone-brief%2FSKILL.md -->"},"items":[{"name":"SKILL.md","path":"gsd-orchestrator/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/gsd-orchestrator/SKILL.md","title":"gsd-orchestrator","category":"anthropic-skill","format":"markdown","content":"---\nname: gsd-orchestrator\ndescription: >\n  Build software products autonomously via GSD headless mode. Handles the full\n  lifecycle: write a spec, launch a build, poll for completion, handle blockers,\n  track costs, and verify the result. Use when asked to \"build something\",\n  \"create a project\", \"run gsd\", \"check build status\", or any task that\n  requires autonomous software development via subprocess.\nmetadata:\n  openclaw:\n    requires:\n      bins: [gsd]\n    install:\n      kind: node\n      package: gsd-pi\n      bins: [gsd]\n---\n\n<objective>\nYou are an autonomous agent that builds software by orchestrating GSD as a subprocess.\nGSD is a headless CLI that plans, codes, tests, and ships software from a spec.\nYou control it via shell commands, exit codes, and JSON output — no SDK, no RPC.\n</objective>\n\n<mental_model>\nGSD headless is a subprocess you launch and monitor. Think of it like a junior developer\nyou hand a spec to:\n\n1. You write the spec (what to build)\n2. You launch the build (`gsd headless ... new-milestone --context spec.md --auto`)\n3. You wait for it to finish (exit code tells you the outcome)\n4. You check the result (query state, inspect files, verify deliverables)\n5. If blocked, you intervene (steer, supply answers, or escalate)\n\nThe subprocess handles all planning, coding, testing, and git commits internally.\nYou never write application code yourself — GSD does that.\n</mental_model>\n\n<critical_rules>\n- **Flags before command.** `gsd headless [--flags] [command] [args]`. Flags after the command are ignored.\n- **Redirect stderr.** JSON output goes to stdout. Progress goes to stderr. Always `2>/dev/null` when parsing JSON.\n- **Check exit codes.** 0=success, 1=error, 10=blocked (needs you), 11=cancelled.\n- **Use `query` to poll.** Instant (~50ms), no LLM cost. Use it between steps, not `auto` for status.\n- **Budget awareness.** Track `cost.total` from query results. Set limits before launching long runs.\n- **One project directory per build.** Each GSD project needs its own directory with a `.gsd/` folder.\n</critical_rules>\n\n<routing>\nRoute based on what you need to do:\n\n**Build something from scratch:**\nRead `workflows/build-from-spec.md` — write spec, init directory, launch, monitor, verify.\n\n**Check on a running or completed build:**\nRead `workflows/monitor-and-poll.md` — query state, interpret phases, handle blockers.\n\n**Execute with fine-grained control:**\nRead `workflows/step-by-step.md` — run one unit at a time with decision points.\n\n**Understand the JSON output:**\nRead `references/json-result.md` — field reference for HeadlessJsonResult.\n\n**Pre-supply answers or secrets:**\nRead `references/answer-injection.md` — answer file schema and injection mechanism.\n\n**Look up a specific command:**\nRead `references/commands.md` — full command reference with flags and examples.\n</routing>\n\n<quick_reference>\n\n**Launch a full build (spec to working code):**\n```bash\nmkdir -p /tmp/my-project && cd /tmp/my-project && git init\ncat > spec.md << 'EOF'\n# Your Product Spec Here\nBuild a ...\nEOF\ngsd headless --output-format json --context spec.md new-milestone --auto 2>/dev/null\n```\n\n**Check project state (instant, free):**\n```bash\ncd /path/to/project\ngsd headless query | jq '{phase: .state.phase, progress: .state.progress, cost: .cost.total}'\n```\n\n**Resume work on an existing project:**\n```bash\ncd /path/to/project\ngsd headless --output-format json auto 2>/dev/null\n```\n\n**Run one step at a time:**\n```bash\nRESULT=$(gsd headless --output-format json next 2>/dev/null)\necho \"$RESULT\" | jq '{status: .status, phase: .phase, cost: .cost.total}'\n```\n\n</quick_reference>\n\n<exit_codes>\n| Code | Meaning | Your action |\n|------|---------|-------------|\n| `0`  | Success | Check deliverables, verify output, report completion |\n| `1`  | Error or timeout | Inspect stderr, check `.gsd/STATE.md`, retry or escalate |\n| `10` | Blocked | Query state for blocker details, steer around it or escalate to human |\n| `11` | Cancelled | Process was interrupted — resume with `--resume <sessionId>` or restart |\n</exit_codes>\n\n<project_structure>\nGSD creates and manages all state in `.gsd/`:\n```\n.gsd/\n  PROJECT.md          # What this project is\n  REQUIREMENTS.md     # Capability contract\n  DECISIONS.md        # Architectural decisions (append-only)\n  KNOWLEDGE.md        # Persistent project knowledge (manual rules, memory-projected patterns/lessons)\n  STATE.md            # Current phase and next action\n  milestones/\n    M001-xxxxx/\n      M001-xxxxx-CONTEXT.md    # Scope, constraints, assumptions\n      M001-xxxxx-ROADMAP.md    # Slices with checkboxes\n      M001-xxxxx-SUMMARY.md    # Completion summary\n      slices/S01/\n        S01-PLAN.md            # Tasks\n        S01-SUMMARY.md         # Slice summary\n        tasks/\n          T01-PLAN.md          # Individual task spec\n          T01-SUMMARY.md       # Task completion summary\n```\n\nState is derived from files on disk — checkboxes in ROADMAP.md and PLAN.md are the source of truth for completion. You never need to edit these files. GSD manages them. But you can read them to understand progress.\n</project_structure>\n\n<flags>\n| Flag | Description |\n|------|-------------|\n| `--output-format <fmt>` | `text` (default), `json` (structured result at exit), `stream-json` (JSONL events) |\n| `--json` | Alias for `--output-format stream-json` — JSONL event stream to stdout |\n| `--bare` | Skip CLAUDE.md, AGENTS.md, user settings, user skills. Use for CI/ecosystem runs. |\n| `--resume <id>` | Resume a prior headless session by its session ID |\n| `--timeout N` | Overall timeout in ms (default: 300000, use 0 to disable) |\n| `--model ID` | Override LLM model |\n| `--supervised` | Forward interactive UI requests to orchestrator via stdout/stdin |\n| `--response-timeout N` | Timeout (ms) for orchestrator response in supervised mode (default: 30000) |\n| `--answers <path>` | Pre-supply answers and secrets from JSON file |\n| `--events <types>` | Filter JSONL to specific event types (comma-separated, implies `--json`) |\n| `--verbose` | Show tool calls in progress output |\n| `--context <path>` | Spec file path for `new-milestone` (use `-` for stdin) |\n| `--context-text <text>` | Inline spec text for `new-milestone` |\n| `--auto` | Chain into auto-mode after `new-milestone` |\n</flags>\n\n<answer_injection>\nPre-supply answers and secrets for fully autonomous runs:\n\n```bash\ngsd headless --answers answers.json --output-format json auto 2>/dev/null\n```\n\n```json\n{\n  \"questions\": { \"question_id\": \"selected_option\" },\n  \"secrets\": { \"API_KEY\": \"sk-...\" },\n  \"defaults\": { \"strategy\": \"first_option\" }\n}\n```\n\n- **questions** — question ID to answer (string for single-select, string[] for multi-select)\n- **secrets** — env var to value, injected into child process environment\n- **defaults.strategy** — `\"first_option\"` (default) or `\"cancel\"` for unmatched questions\n\nSee `references/answer-injection.md` for the full mechanism.\n</answer_injection>\n\n<event_streaming>\nFor real-time monitoring, use JSONL event streaming:\n\n```bash\ngsd headless --json auto 2>/dev/null | while read -r line; do\n  TYPE=$(echo \"$line\" | jq -r '.type')\n  case \"$TYPE\" in\n    tool_execution_start) echo \"Tool: $(echo \"$line\" | jq -r '.toolName')\" ;;\n    extension_ui_request) echo \"GSD: $(echo \"$line\" | jq -r '.message // .title // empty')\" ;;\n    agent_end) echo \"Session ended\" ;;\n  esac\ndone\n```\n\nFilter to specific events: `--events agent_end,execution_complete,extension_ui_request`\n\nAvailable types: `agent_start`, `agent_end`, `tool_execution_start`, `tool_execution_end`,\n`tool_execution_update`, `extension_ui_request`, `message_start`, `message_end`,\n`message_update`, `turn_start`, `turn_end`, `cost_update`, `execution_complete`.\n</event_streaming>\n\n<all_commands>\n| Command | Purpose |\n|---------|---------|\n| `auto` | Run all queued units until milestone complete or blocked (default) |\n| `next` | Run exactly one unit, then exit |\n| `query` | Instant JSON snapshot — state, next dispatch, costs (no LLM, ~50ms) |\n| `new-milestone` | Create milestone from spec file |\n| `dispatch <phase>` | Force specific phase (research, plan, execute, complete, reassess, uat, replan) |\n| `stop` / `pause` | Control auto-mode |\n| `steer <desc>` | Hard-steer plan mid-execution |\n| `skip` / `undo` | Unit control |\n| `queue` | Queue/reorder milestones |\n| `history` | View execution history |\n| `doctor` | Health check + auto-fix |\n| `knowledge <rule\\|pattern\\|lesson>` | Add persistent project knowledge |\n\nSee `references/commands.md` for the complete reference.\n</all_commands>\n","frontmatter":{"name":"gsd-orchestrator","description":"Build software products autonomously via GSD headless mode. Handles the full lifecycle: write a spec, launch a build, poll for completion, handle blockers, track costs, and verify the result. Use when asked to \"build something\", \"create a project\", \"run gsd\", \"check build status\", or any task that requires autonomous software development via subprocess.\n","metadata":{"openclaw":{"requires":{"bins":["gsd"]},"install":{"kind":"node","package":"gsd-pi","bins":["gsd"]}}}},"isInternal":false,"tokens":2201,"sizeBytes":8584},{"name":"claude-marketplace-import.md","path":"src/resources/extensions/gsd/docs/claude-marketplace-import.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/extensions/gsd/docs/claude-marketplace-import.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"# Claude Marketplace Import\n\nThis document describes the Claude marketplace import feature in GSD: what it reads, what it imports, what it persists, and what it does not translate into active GSD/Pi runtime behavior.\n\n---\n\n## What this feature does\n\nGSD can read Claude Code marketplace catalogs, inspect the plugins they reference, and import selected Claude skills into GSD/Pi while preserving Claude-style namespace identity.\n\nThe interactive entry point is:\n\n```text\n/gsd prefs import-claude\n```\n\nYou can also choose scope explicitly:\n\n```text\n/gsd prefs import-claude global\n/gsd prefs import-claude project\n```\n\n---\n\n## Claude Code model this feature follows\n\nAnthropic documents Claude marketplaces as sources users add with:\n\n```text\n/plugin marketplace add <github repo or local path>\n```\n\nA marketplace contains a catalog at:\n\n```text\n.claude-plugin/marketplace.json\n```\n\nAnthropic distinguishes between:\n\n- **Marketplace source** — where Claude fetches `marketplace.json`\n- **Plugin source** — where Claude fetches each plugin listed in that marketplace\n- **Installed plugin cache** — Claude copies installed plugin payloads into:\n\n```text\n~/.claude/plugins/cache\n```\n\nAnthropic also documents user-added marketplace sources under:\n\n```text\n~/.claude/plugins/marketplaces\n```\n\nGSD aligns its Claude import flow to that model.\n\n---\n\n## Where GSD looks\n\nFor Claude plugin and marketplace material, GSD prefers Claude-managed locations first:\n\n1. `~/.claude/plugins/marketplaces`\n2. `~/.claude/plugins/cache`\n3. `~/.claude/plugins`\n\nAfter that, GSD still allows local clone-style convenience paths such as sibling repos or `~/repos/...` paths. Those fallbacks remain supported for developer workflows, but they are not the primary Claude storage model.\n\n---\n\n## What GSD imports\n\n### Imported into GSD/Pi settings\n\n- Claude skills discovered directly from configured skill roots\n- Marketplace-derived skills\n\nImported marketplace skills preserve canonical namespace identity, for example:\n\n```text\npython3-development:stinkysnake\nscientific-method:experiment-protocol\n```\n\n### Discovered, modeled, and validated\n\n- Marketplace-derived agents\n\n### Discovered but not translated into active Pi-native runtime behavior\n\n- hooks\n- MCP server definitions\n- LSP server definitions\n- other plugin metadata that does not currently map directly into active GSD/Pi runtime surfaces\n\n---\n\n## Import flow\n\nThe import flow does the following:\n\n1. discover Claude skills and marketplace/plugin roots\n2. identify marketplace roots by checking for `.claude-plugin/marketplace.json`\n3. inspect discovered plugins and inventory their components\n4. let you select components to import\n5. validate the selection for canonical conflicts and ambiguity\n6. persist imported resources into GSD/Pi settings\n\n---\n\n## Namespace behavior\n\nGSD preserves Claude plugin namespace semantics rather than flattening plugin components into anonymous global names.\n\n### Canonical references\n\nCanonical references remain available for imported components:\n\n- skills: `plugin-name:skill-name`\n- agents: `plugin-name:agent-name`\n\n### Shorthand\n\nGSD supports shorthand lookup when it is unambiguous.\n\n### Local-first resolution\n\nWhen a namespaced component refers to another component by bare name, GSD tries the same plugin namespace first before broader lookup.\n\n---\n\n## Important safeguard: marketplace agent directories are not stored as package sources\n\nClaude plugin agent directories are markdown agent-definition directories, for example:\n\n```text\n.../plugins/python3-development/agents\n```\n\nGSD does **not** persist imported marketplace agent directories into:\n\n```json\nsettings.packages\n```\n\nThis is intentional.\n\n### Why\n\nPersisting an `.../agents` directory into `settings.packages` can cause Pi startup to treat that directory as an extension/package root. In real host validation, that produced extension loader failures such as:\n\n```text\nCannot find module '.../agents'\n```\n\nGSD now avoids writing those entries.\n\n---\n\n## Settings effects\n\n### Skills\n\nImported skills are persisted into Pi skill settings. Depending on the selection path, they may also be added to GSD preferences.\n\n### Marketplace agents\n\nMarketplace agents remain part of the import model and validation surface, but their `agents/` directories are not persisted as package roots.\n\n---\n\n## Diagnostics\n\nGSD distinguishes between:\n\n- **canonical conflicts** — hard errors\n- **shorthand overlaps** — warnings when canonical names remain distinct\n- **alias conflicts** — diagnostics for alias collisions or shadowing\n\nThis allows imported marketplace content to be validated without reporting valid overlap as fatal breakage.\n\n---\n\n## Verification status of this feature\n\nThis feature has been verified in three ways:\n\n1. **Contract/unit tests** for parsing, namespacing, resolution, diagnostics, and import behavior\n2. **Portable integration-style tests** using local or cloned marketplace fixtures\n3. **Real host validation** against the installed `gsd` binary and actual Claude-managed directories on the host machine\n\nReal host validation included:\n\n- clean startup of the installed `gsd` binary after fixing stale bad settings\n- successful invocation of an imported skill (`/stinkysnake`)\n- successful execution of `/gsd prefs import-claude global`\n- verification that imported marketplace agent directories were **not** reintroduced into `settings.packages`\n\n---\n\n## Current limitations\n\n- GSD does not yet translate every Claude plugin component type into active Pi-native runtime behavior\n- marketplace-derived agents are not persisted as package roots, by design\n- clone-style local fallbacks still exist for developer convenience, even though Claude-managed marketplace/plugin locations are preferred first\n\n---\n\n## References\n\n- Anthropic: Claude Code settings\n- Anthropic: Create and distribute a plugin marketplace\n- Anthropic: Plugins and plugin reference\n","isInternal":false,"tokens":1203,"sizeBytes":5930},{"name":"COORDINATION.md","path":"src/resources/extensions/gsd/docs/COORDINATION.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/extensions/gsd/docs/COORDINATION.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"# Auto-mode coordination is single-host\n\nThe DB-backed coordination tables introduced by Phase B (`workers`,\n`milestone_leases`, `unit_dispatches`, `cancellation_requests`,\n`command_queue`) and the supporting `runtime_kv` table from Phase C all\nrely on **shared SQLite WAL on local disk**. They do not work across\nmachines.\n\n## Why single-host only\n\n- SQLite WAL coordination — the locking primitives that make\n  `claimMilestoneLease`, `recordDispatchClaim`, and `claimNextCommand`\n  atomic — is local-disk only. Network filesystems (NFS, SMB, S3FS) and\n  fuse mounts break the lock semantics that the WAL relies on.\n- Heartbeat TTL (`workers.last_heartbeat_at`) compares timestamps written\n  with SQLite wall-clock time (`datetime('now')`). Across machines without\n  wall-clock synchronization (for example NTP/chrony), TTL filtering can\n  produce phantom-active or premature-crashed verdicts. Monotonic clocks\n  are not used for these comparisons.\n- Fencing tokens (`milestone_leases.fencing_token`) are monotonically\n  ordered by SQL within a single transaction. Cross-host races could\n  produce duplicate tokens if two SQLite processes opened the same DB\n  on a network mount.\n\n## What does work\n\n- Multiple `gsd auto` worker processes on the **same machine**, sharing\n  the project's SQLite DB via WAL. The lease check refuses concurrent\n  claims on the same milestone; the dispatch ledger's partial unique\n  index refuses double-claims of the same unit.\n- A single `gsd auto` worker plus arbitrary read-only consumers\n  (dashboards, doctors) on the same machine.\n- Worktree-based parallelism on the same machine, where each worker\n  holds a different milestone lease.\n\n## Multi-host alternatives\n\nIf you need to coordinate `gsd auto` workers across machines, you need\na real coordinator: Postgres for the ledger + a leader-election service\n(etcd, Consul) for the leases. That's out of scope for these phases.\nThe schema and module shapes here would need a non-trivial backend\nswap before they could ride on top of either.\n","isInternal":false,"tokens":461,"sizeBytes":2032},{"name":"preferences-reference.md","path":"src/resources/extensions/gsd/docs/preferences-reference.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/extensions/gsd/docs/preferences-reference.md","title":"Docs Skill","category":"anthropic-skill","format":"markdown","content":"# GSD Preferences Reference\n\nFull documentation for `~/.gsd/PREFERENCES.md` (global) and `.gsd/PREFERENCES.md` (project).\n\n---\n\n## Notes\n\n- Keep this skill-first.\n- Prefer explicit skill names or absolute paths.\n- Use absolute paths for personal/local skills when you want zero ambiguity.\n- These preferences guide which skills GSD should load and follow; they do not override higher-priority instructions in the current conversation.\n- For Claude marketplace/plugin import behavior, see `~/.gsd/agent/extensions/gsd/docs/claude-marketplace-import.md`.\n\n---\n\n## Semantics\n\n### Empty Arrays vs Omitted Fields\n\n**Empty arrays (`[]`) are equivalent to omitting the field entirely.** During validation, GSD deletes empty arrays from the preferences object (see `validatePreferences()` in `preferences.ts`):\n\n```typescript\nfor (const key of [\n  \"always_use_skills\",\n  \"prefer_skills\",\n  \"avoid_skills\",\n  \"custom_instructions\",\n] as const) {\n  if (validated[key] && validated[key]!.length === 0) {\n    delete validated[key];\n  }\n}\n```\n\nThese are functionally identical:\n\n```yaml\n# Explicit empty arrays — will be normalized away\nprefer_skills: []\navoid_skills: []\nskill_rules: []\n\n# Omitted entirely — same result\n# (just don't write these fields)\n```\n\n**Recommendation:** Omit fields you don't need. Empty arrays add noise with no effect.\n\n### Global vs Project Preferences\n\nPreferences are loaded from two locations and merged:\n\n1. **Global:** `~/.gsd/PREFERENCES.md` — applies to all projects\n2. **Project:** `.gsd/PREFERENCES.md` — applies to the current project only\n\n**Merge behavior** (see `mergePreferences()` in `preferences.ts`):\n\n- **Scalar fields** (`skill_discovery`, `budget_ceiling`, etc.): Project wins if defined, otherwise global. Uses nullish coalescing (`??`).\n- **Array fields** (`always_use_skills`, `prefer_skills`, etc.): Concatenated via `mergeStringLists()` (global first, then project).\n- **Object fields** (`models`, `git`, `auto_supervisor`): Shallow merge via spread operator `{ ...base, ...override }`.\n\nFor `models`, project settings override global at the phase level. If global has `planning: opus` and project has `planning: sonnet`, the project wins. But if project omits `research`, global's `research` setting is preserved.\n\n### Skill Discovery vs Skill Preferences\n\nThese are **separate concerns**:\n\n| Field                                                | What it controls                                          | Code reference                                           |\n| ---------------------------------------------------- | --------------------------------------------------------- | -------------------------------------------------------- |\n| `skill_discovery`                                    | **Whether** GSD looks for relevant skills during research | `resolveSkillDiscoveryMode()` in `preferences.ts`        |\n| `always_use_skills`, `prefer_skills`, `avoid_skills` | **Which** skills to use when they're found relevant       | `renderPreferencesForSystemPrompt()` in `preferences.ts` |\n\nSetting `prefer_skills: []` does **not** disable skill discovery — it just means you have no preference overrides. Use `skill_discovery: off` to disable discovery entirely.\n\n---\n\n## Field Guide\n\n- `version`: schema version. Start at `1`.\n\n- `mode`: workflow mode — `\"solo\"` or `\"team\"`. Sets sensible defaults for git and project settings based on your workflow. Mode defaults are the lowest priority layer — any explicit preference overrides them. Omit to configure everything manually.\n\n  | Setting                | `solo`       | `team`       |\n  | ---------------------- | ------------ | ------------ |\n  | `git.auto_push`        | `true`       | `false`      |\n  | `git.push_branches`    | `false`      | `true`       |\n  | `git.pre_merge_check`  | `false`      | `true`       |\n  | `git.merge_strategy`   | `\"squash\"`   | `\"squash\"`   |\n  | `git.isolation`        | `\"none\"`     | `\"none\"`     |\n  | `unique_milestone_ids` | `false`      | `true`       |\n\n  Quick setup: `/gsd mode` (global) or `/gsd mode project` (project-level).\n\n- `always_use_skills`: skills GSD should use whenever they are relevant.\n\n- `prefer_skills`: soft defaults GSD should prefer when relevant.\n\n- `avoid_skills`: skills GSD should avoid unless clearly needed.\n\n- `skill_rules`: situational rules with a human-readable `when` trigger and one or more of `use`, `prefer`, or `avoid`.\n\n- `custom_instructions`: extra durable instructions related to skill use. For operational project knowledge, use `.gsd/KNOWLEDGE.md` instead. Rules are file-canonical; patterns and lessons are persisted to the `memories` table and projected back into `KNOWLEDGE.md` on the next session start.\n\n- `language`: preferred response language for all GSD interactions. Accepts any language name or code — `\"Chinese\"`, `\"zh\"`, `\"German\"`, `\"de\"`, `\"日本語\"`, etc. When set, GSD injects \"Always respond in \\<language\\>\" into every agent's system prompt, including after `/clear`. Quickest way to set it: `/gsd language <name>`. To clear: `/gsd language off`.\n\n- `models`: per-stage model selection (applies to both auto-mode and guided-flow dispatches). Keys: `research`, `planning`, `discuss`, `execution`, `execution_simple`, `completion`, `validation`, `subagent`. Values can be:\n  - Simple string: `\"claude-sonnet-4-6\"` — single model, no fallbacks\n  - Provider-qualified string: `\"bedrock/claude-sonnet-4-6\"` — targets a specific provider when the same model ID exists across multiple providers\n  - Object with fallbacks: `{ model: \"claude-opus-4-6\", fallbacks: [\"glm-5\", \"minimax-m2.5\"] }` — tries fallbacks in order if primary fails\n  - Object with provider: `{ model: \"claude-opus-4-6\", provider: \"bedrock\" }` — explicit provider targeting in object format\n  - Omit a key to use whatever model is currently active (except `discuss` and `validation` which fall back to `planning` when unset). Fallbacks are tried when model switching fails (provider unavailable, rate limited, etc.).\n  - `discuss` — used for milestone/slice discussion (interactive context gathering). Falls back to `planning` if unset.\n  - `validation` — used for gate evaluation, roadmap reassessment, milestone validation, and doc rewrites. Falls back to `planning` if unset.\n\n- `skill_staleness_days`: number — skills unused for this many days get deprioritized during discovery. Set to `0` to disable staleness tracking. Default: `60`.\n\n- `skill_discovery`: controls how GSD discovers and applies skills during auto-mode. Valid values:\n  - `auto` — skills are found and applied automatically without prompting.\n  - `suggest` — (default) skills are identified during research but not installed automatically.\n  - `off` — skill discovery is disabled entirely.\n\n- `auto_supervisor`: configures the auto-mode supervisor that monitors agent progress and enforces timeouts. Keys:\n  - `model`: model ID to use for the supervisor process (defaults to the currently active model).\n  - `soft_timeout_minutes`: minutes before the supervisor issues a soft warning (default: 20).\n  - `idle_timeout_minutes`: minutes of inactivity before the supervisor intervenes (default: 10).\n  - `hard_timeout_minutes`: minutes before the supervisor forces termination (default: 30).\n\n- `min_request_interval_ms`: number — minimum integer milliseconds between auto-mode LLM request dispatches. Non-integer values are rounded down (e.g., `1000.9 → 1000`). Use this to proactively slow auto-mode on rate-limited providers and reduce 429 errors. Set to `0` to disable. Default: `0` (disabled).\n\n- `git`: configures GSD's git behavior. All fields are optional — omit any to use defaults. Keys:\n  - `auto_push`: boolean — automatically push commits to the remote after committing. Default: `false`.\n  - `push_branches`: boolean — push the milestone branch to the remote after commits. Default: `false`.\n  - `remote`: string — git remote name to push to. Default: `\"origin\"`.\n  - `snapshots`: boolean — create WIP snapshot commits (e.g. pre-dispatch and stale-uncommitted-changes safety commits emitted by the doctor). Set to `false` to suppress all doctor-initiated `gsd snapshot:` commits. Default: `true`.\n  - `pre_merge_check`: boolean or `\"auto\"` — run pre-merge checks before merging a worktree back to the integration branch. `true` always runs, `false` never runs, `\"auto\"` runs when CI is detected. Default: `\"auto\"`.\n  - `commit_type`: string — override the conventional commit type prefix. Must be one of: `feat`, `fix`, `refactor`, `docs`, `test`, `chore`, `perf`, `ci`, `build`, `style`. Default: inferred from diff content.\n  - `main_branch`: string — the primary branch name for new git repos (e.g., `\"main\"`, `\"master\"`, `\"trunk\"`). Also used by `getMainBranch()` as the preferred branch when auto-detection is ambiguous. Default: `\"main\"`.\n  - `merge_strategy`: `\"squash\"` or `\"merge\"` — controls how worktree branches are merged back. `\"squash\"` combines all commits into one; `\"merge\"` preserves individual commits. Default: `\"squash\"`.\n  - `isolation`: `\"none\"`, `\"worktree\"`, or `\"branch\"` — controls auto-mode git isolation strategy. `\"none\"` works directly on the current branch with no worktree or milestone branch (default, ideal for step-mode with hot reloads); `\"worktree\"` creates a milestone worktree for isolated work; `\"branch\"` works directly in the project root but creates a milestone branch (useful for submodule-heavy repos). `worktree` requires a committed `HEAD`; in a zero-commit repo, GSD temporarily treats it as `none` until the first commit exists. Default: `\"none\"`.\n  - `manage_gitignore`: boolean — when `false`, GSD will not touch `.gitignore` at all. Useful when your project has a strictly managed `.gitignore` and you don't want GSD adding entries. Default: `true`.\n  - `worktree_post_create`: string — script to run after a worktree is created (both auto-mode and manual `/worktree`). Receives `SOURCE_DIR` and `WORKTREE_DIR` as environment variables. Can be absolute or relative to project root. Runs with 30-second timeout. Failure is non-fatal (logged as warning). Default: none.\n  - `auto_pr`: boolean — automatically create a GitHub pull request after a milestone branch is merged. Requires `gh` CLI to be installed. Default: `false`.\n  - `pr_target_branch`: string — branch to target when `auto_pr` is enabled. Defaults to `main_branch` when omitted.\n  - **Deprecated:** `commit_docs` — no longer valid; `.gsd/` is always gitignored. Remove this setting.\n  - **Deprecated:** `merge_to_main` — no longer valid; milestone-level merge is always used. Remove this setting.\n\n- `workspace`: configures multi-repository parent workspaces. Keys:\n  - `mode`: `\"project\"` (default single-repo behavior) or `\"parent\"` (one `.gsd` controlling child repos).\n  - `repositories`: object map of repository IDs to config.\n    - Repository ID format: `^[A-Za-z0-9][A-Za-z0-9._-]*$`.\n    - Reserved ID: `project` is implicit and always maps to the project root; user-defined `workspace.repositories.project` is rejected.\n    - `path`: required relative path that must resolve within the project root (paths escaping via `..` are rejected).\n    - `role`: optional short description of what the repo owns.\n    - `verification`: optional array of verification commands for that repo.\n    - `commit_policy`: optional `\"auto\"` or `\"skip\"` to include or skip commit actions per repo.\n\n## Workspace Example\n\n```yaml\n---\nversion: 1\nworkspace:\n  mode: parent\n  repositories:\n    frontend:\n      path: frontend\n      role: web UI\n      verification:\n        - npm test\n        - npm run lint\n      commit_policy: auto\n    backend:\n      path: ./backend\n      role: API server\n      verification:\n        - go test ./...\n      commit_policy: auto\n---\n```\n\nThis config sets a parent workspace with two child repositories. The implicit `project` repository is always created for the project root and cannot be user-defined.\n\n- `unique_milestone_ids`: boolean — when `true`, generates milestone IDs in `M{seq}-{rand6}` format (e.g. `M001-eh88as`) instead of plain sequential `M001`. Prevents ID collisions in team workflows where multiple contributors create milestones concurrently. Both formats coexist — existing `M001`-style milestones remain valid. Default: `false`.\n\n- `budget_ceiling`: number — maximum dollar amount to spend on auto-mode. When reached, behavior is controlled by `budget_enforcement`. Default: no limit.\n\n- `budget_enforcement`: `\"warn\"`, `\"pause\"`, or `\"halt\"` — action taken when `budget_ceiling` is reached.\n  - `warn` — log a warning but continue execution.\n  - `pause` — pause auto-mode and wait for user confirmation.\n  - `halt` — stop auto-mode immediately.\n  - Default: `\"pause\"`.\n\n- `context_pause_threshold`: number (`0` or `1-100`) — live context window usage percentage at which auto-mode should pause to suggest checkpointing. Set to `0` to disable. Use whole percentages like `75`, not fractional ratios like `0.75`. Default: `0` (disabled).\n\n- `token_profile`: `\"budget\"`, `\"balanced\"`, `\"quality\"`, or `\"burn-max\"` — coordinates model selection, phase skipping, and context compression. `budget` skips research/reassessment and uses cheaper models; `balanced` (default) skips research/reassessment to reduce token burn; `quality` prefers higher-quality models; `burn-max` keeps full-context defaults, disables downgrade routing, and keeps phase skips off.\n\n- `planning_depth`: `\"light\"` or `\"deep\"` — controls project-level discovery before milestone planning. `\"light\"` is the default milestone discussion flow. `\"deep\"` runs workflow preferences, project discussion, requirements discussion, a research-decision gate, and optional project research before milestone planning. Enable it with `/gsd new-project --deep`, `/gsd new-milestone --deep`, or by setting `planning_depth: deep` in project-local `.gsd/PREFERENCES.md`. Global `~/.gsd/PREFERENCES.md` does not opt every fresh repo into deep mode. Deep mode writes `.gsd/PROJECT.md`, `.gsd/REQUIREMENTS.md`, `.gsd/runtime/research-decision.json`, and, when research is approved, `.gsd/research/STACK.md`, `FEATURES.md`, `ARCHITECTURE.md`, and `PITFALLS.md`.\n\n- `phases`: fine-grained control over which phases run. Usually set by `token_profile`, but can be overridden. Keys:\n  - `skip_research`: boolean — skip milestone-level research. Default: `false`.\n  - `reassess_after_slice`: boolean — run a dedicated roadmap-reassessment unit after each completed slice. Default: `false` (per ADR-003 §4). The plan-slice agent for the next slice performs JIT reassessment via a prompt preamble at zero additional token cost; a dedicated reassess session is opt-in. Set to `true` (e.g. via the `burn-max` profile) if you want the explicit session.\n  - `skip_reassess`: boolean — force-disable roadmap reassessment even if `reassess_after_slice` is enabled. Default: `false`.\n  - `skip_slice_research`: boolean — skip per-slice research. Default: `false`.\n\n- `reactive_execution`: controls automatic parallel task dispatch inside a slice. Reactive execution is enabled by default when omitted; set `enabled: false` to opt out. With default-on behavior, GSD only attempts a reactive batch when at least three ready tasks are available and the task-plan IO graph is non-ambiguous. If you set `enabled: true` explicitly, GSD uses the earlier opt-in threshold of two ready tasks. Keys:\n  - `enabled`: boolean — set `false` to force sequential task execution. Default: `true`.\n  - `max_parallel`: number — maximum tasks to dispatch in one batch, range `1`-`8`. Default: `2`.\n  - `isolation_mode`: `\"same-tree\"` — currently the only supported value.\n  - `subagent_model`: string — optional model override for reactive task subagents. Falls back to the `models.subagent` routing when omitted.\n\n- `remote_questions`: route interactive questions to Slack/Discord for headless auto-mode. Keys:\n  - `channel`: `\"slack\"` or `\"discord\"` — channel type.\n  - `channel_id`: string or number — channel ID.\n  - `timeout_minutes`: number — question timeout in minutes (clamped 1-30).\n  - `poll_interval_seconds`: number — poll interval in seconds (clamped 2-30).\n\n- `notifications`: configures desktop notification behavior during auto-mode. Keys:\n  - `enabled`: boolean — master toggle for all notifications. Default: `true`.\n  - `on_complete`: boolean — notify when a unit completes. Default: `true`.\n  - `on_error`: boolean — notify on errors. Default: `true`.\n  - `on_budget`: boolean — notify when budget thresholds are reached. Default: `true`.\n  - `on_milestone`: boolean — notify when a milestone finishes. Default: `true`.\n  - `on_attention`: boolean — notify when manual attention is needed. Default: `true`.\n  - Terminal auto-loop errors persist an `activity/*-auto-crash-note.json` file with error/session metadata; when available, the error notification includes the crash-note path and instructs resuming with `/gsd auto`.\n\n- `cmux`: configures cmux terminal integration when GSD is running inside a cmux workspace. Keys:\n  - `enabled`: boolean — master toggle for cmux integration. Default: `false`.\n  - `notifications`: boolean — route desktop notifications through cmux. Default: `true` when enabled.\n  - `sidebar`: boolean — publish status, progress, and log metadata to the cmux sidebar. Default: `true` when enabled.\n  - `splits`: boolean — run supported subagent work in visible cmux splits. Default: `false`.\n  - `browser`: boolean — reserve the future browser integration flag. Default: `false`.\n\n- `dynamic_routing`: configures the dynamic model router that adjusts model selection based on task complexity. Keys:\n  - `enabled`: boolean — enable dynamic routing. Default: `false`.\n  - `tier_models`: object — model overrides per complexity tier. Keys: `light`, `standard`, `heavy`. Values are model ID strings.\n  - `escalate_on_failure`: boolean — escalate to a higher-tier model when the current one fails. Default: `true`.\n  - `budget_pressure`: boolean — downgrade model tier when budget is under pressure. Default: `true`.\n  - `cross_provider`: boolean — allow routing across different providers. Default: `true`.\n  - `hooks`: boolean — enable routing hooks. Default: `true`.\n  - `capability_routing`: boolean — enable capability-profile scoring for model selection within a tier. Requires `enabled: true`. Default: `false`.\n\n- `disabled_model_providers`: string[] — provider IDs to hide from model selection and routing (for example `[\"google-gemini-cli\"]`). This only affects model availability (`/model`, auto-model selection, routing); it does not disable tool auth flows like `google_search`.\n\n- `uok`: Unified Orchestration Kernel controls. Keys:\n  - `enabled`: boolean — enable kernel wrappers and contract observers. Default: `true`.\n  - `legacy_fallback.enabled`: boolean — emergency release fallback that forces legacy orchestration behavior even when `uok.enabled` is `true`. Default: `false`.\n    - Runtime override: set `GSD_UOK_FORCE_LEGACY=1` (or `GSD_UOK_LEGACY_FALLBACK=1`) to force legacy behavior for the current process.\n  - `gates.enabled`: boolean — route checks through the unified gate runner and persist `gate_runs`. Default: `true`.\n  - `model_policy.enabled`: boolean — enforce policy filtering before model capability scoring. Default: `true`.\n  - `execution_graph.enabled`: boolean — enable DAG scheduler facade/adapters for execution. Default: `true`.\n  - `gitops.enabled`: boolean — persist turn-level git transaction records. Default: `true`.\n  - `gitops.turn_action`: `\"commit\"` | `\"snapshot\"` | `\"status-only\"` — turn transaction mode. Default: `\"commit\"` (per-task atomic commits).\n  - `gitops.turn_push`: boolean — whether turn transactions should include push intent metadata. Default: `false`.\n  - `audit_unified.enabled`: boolean — dual-write unified audit envelope events. Default: `true`.\n  - `plan_v2.enabled`: boolean — enable bounded clarify/research/draft/compile planning flow. Default: `true`.\n\n- `context_management`: configures context hygiene for auto-mode sessions. Keys:\n  - `observation_masking`: boolean — mask old tool results to reduce context bloat. Default: `true`.\n  - `observation_mask_turns`: number — keep this many recent turns verbatim (1-50). Default: `8`.\n  - `compaction_threshold_percent`: number — trigger compaction at this % of context window (0.5-0.95). Lower values fire compaction earlier, reducing drift. Default: `0.60`.\n  - `tool_result_max_chars`: number — max chars per tool result in GSD sessions (200-10000). Default: `800`.\n\n- `auto_visualize`: boolean — show a visualizer hint after each milestone completion in auto-mode. Default: `false`.\n\n- `auto_report`: boolean — generate an HTML report snapshot after each milestone completion. Default: `true`.\n\n- `search_provider`: `\"brave\"`, `\"tavily\"`, `\"ollama\"`, `\"native\"`, or `\"auto\"` — selects the search backend for research phases. `\"native\"` forces Anthropic's built-in web search only; provider values force that backend and disable native search; `\"auto\"` uses the default heuristic. Default: `\"auto\"`.\n\n- `context_selection`: `\"full\"` or `\"smart\"` — controls how files are inlined into context. `\"full\"` inlines entire files; `\"smart\"` uses semantic chunking to include only the most relevant sections. Default is derived from `token_profile`.\n\n- `parallel`: configures parallel orchestration for running multiple slices concurrently. Keys:\n  - `enabled`: boolean — enable parallel execution. Default: `false`.\n  - `max_workers`: number — maximum concurrent workers (1-4). Default: `2`.\n  - `budget_ceiling`: number — optional per-parallel-run budget ceiling.\n  - `merge_strategy`: `\"per-slice\"` or `\"per-milestone\"` — when to merge worktree results back. Default: `\"per-milestone\"`.\n  - `auto_merge`: `\"auto\"`, `\"confirm\"`, or `\"manual\"` — merge behavior after completion. `\"auto\"` merges immediately; `\"confirm\"` asks first; `\"manual\"` leaves branches for you. Default: `\"confirm\"`.\n  - `worker_model`: string — optional model override for parallel milestone workers. When set, workers use this model (e.g. `\"claude-haiku-4-5\"`) instead of inheriting the coordinator's model. Useful for cost savings on execution-heavy milestones.\n\n- `workspace`: repository-scoping for parent/multi-repo workspaces. Keys:\n  - `mode`: `\"project\"` | `\"parent\"` — enables single-repo (default) or parent workspace behavior.\n  - `repositories`: map of repository IDs to repository config:\n    - `path`: string (required) — path relative to project root.\n    - `role`: string (optional) — informational role label.\n    - `verification`: string[] (optional) — repository-specific verification commands used when global `verification_commands` is not set.\n    - `commit_policy`: `\"auto\"` | `\"skip\"` (optional) — per-repository closeout commit behavior.\n  - `project` is always an implicit repository target mapped to the project root for backward compatibility.\n  - Plan/task `targetRepositories` defaults to `[\"project\"]` when omitted.\n\n- `verification_commands`: string[] — shell commands to run as verification after task execution (e.g., `[\"npm test\", \"npm run lint\"]`). Commands run in order; if any fails, the task is marked as needing fixes.\n\n- `verification_auto_fix`: boolean — when `true`, automatically attempt to fix verification failures instead of just reporting them. Default: `false`.\n\n- `verification_max_retries`: number — maximum number of fix-and-retry cycles for verification failures. Default: `0` (no retries).\n\n- `per_unit_cost_cap_usd`: number — per-unit retry cost ceiling in USD for verification retries. Must be a positive finite number when set; invalid values are rejected during preference validation. Default: `5.0`. During auto-verification and artifact-retry flows, auto-mode pauses when the current unit reaches this cap or when current unit cost spikes to at least `3.0x` the rolling average.\n\n- `uat_dispatch`: boolean — when `true`, enables UAT (User Acceptance Testing) dispatch mode. Default: `false`.\n\n- `post_unit_hooks`: array — hooks that fire after a unit completes. Each entry has:\n  - `name`: string — unique hook identifier.\n  - `after`: string[] — unit types that trigger this hook (e.g., `[\"execute-task\"]`).\n  - `prompt`: string — prompt sent to the LLM. Supports `{milestoneId}`, `{sliceId}`, `{taskId}` substitutions.\n  - `max_cycles`: number — max times this hook fires per trigger (default: 1, max: 10).\n  - `model`: string — optional model override.\n  - `artifact`: string — expected output file name (relative to task/slice dir). Hook is skipped if file already exists (idempotent).\n  - `retry_on`: string — if this file is produced instead of the artifact, re-run the trigger unit then re-run hooks.\n  - `agent`: string — agent definition file to use for hook execution.\n  - `enabled`: boolean — toggle without removing (default: `true`).\n\n- `pre_dispatch_hooks`: array — hooks that fire before a unit is dispatched. Each entry has:\n  - `name`: string — unique hook identifier.\n  - `before`: string[] — unit types to intercept.\n  - `action`: `\"modify\"`, `\"skip\"`, or `\"replace\"` — what to do with the unit.\n  - `prepend`: string — text prepended to unit prompt (for `\"modify\"` action).\n  - `append`: string — text appended to unit prompt (for `\"modify\"` action).\n  - `prompt`: string — replacement prompt (for `\"replace\"` action; required when action is `\"replace\"`).\n  - `unit_type`: string — override unit type label (for `\"replace\"` action).\n  - `skip_if`: string — for `\"skip\"` action: only skip if this file exists (relative to unit dir).\n  - `model`: string — optional model override when this hook fires.\n  - `enabled`: boolean — toggle without removing (default: `true`).\n\n  **Action validation:**\n  - `\"modify\"` requires at least one of `prepend` or `append`.\n  - `\"replace\"` requires `prompt`.\n  - `\"skip\"` is valid with no additional fields.\n\n  **Known unit types for `before`/`after`:** `research-milestone`, `plan-milestone`, `research-slice`, `plan-slice`, `execute-task`, `complete-slice`, `replan-slice`, `reassess-roadmap`, `run-uat`.\n\n- `experimental`: opt-in experimental features. All features here are **off by default** — you must explicitly set each one to `true` to enable it. Features in this block may change or be removed without a deprecation cycle while in experimental status. Keys:\n  - `rtk`: boolean — enable RTK (Real-Time Kompression) shell-command compression. When enabled, GSD wraps shell commands through the RTK binary to reduce token usage during command execution. RTK is downloaded automatically on first use if not already installed. **Default: `false`** (opt-in required). Set `GSD_RTK_DISABLED=1` in the environment to force-disable regardless of this preference.\n\n---\n\n## Best Practices\n\n- Keep `always_use_skills` short.\n- Use `skill_rules` for situational routing, not broad personality preferences.\n- Prefer skill names for stable built-in skills.\n- Prefer absolute paths for local personal skills.\n- **Omit fields you don't need** — empty arrays add noise with no effect.\n\n---\n\n## Workflow Mode Examples\n\n**Solo developer — auto-push, simple IDs:**\n\n```yaml\n---\nversion: 1\nmode: solo\n---\n```\n\nEquivalent to setting `git.auto_push: true`, `git.push_branches: false`, `git.pre_merge_check: false`, `git.merge_strategy: squash`, `git.isolation: none`, `unique_milestone_ids: false`.\n\n**Team — unique IDs, push branches, pre-merge checks:**\n\n```yaml\n---\nversion: 1\nmode: team\n---\n```\n\nEquivalent to setting `git.auto_push: false`, `git.push_branches: true`, `git.pre_merge_check: true`, `git.merge_strategy: squash`, `git.isolation: none`, `unique_milestone_ids: true`.\n\n**Mode with overrides — team mode but with auto-push:**\n\n```yaml\n---\nversion: 1\nmode: team\ngit:\n  auto_push: true\n---\n```\n\nGets all team defaults except `auto_push`, which is explicitly overridden to `true`. Any explicit setting always wins over the mode default.\n\n---\n\n## Minimal Example\n\nThe cleanest preferences file only specifies what you actually want:\n\n```yaml\n---\nversion: 1\nalways_use_skills:\n  - debug-like-expert\nskill_discovery: suggest\nmodels:\n  planning: claude-opus-4-6\n  execution: claude-sonnet-4-6\n---\n```\n\nEverything else uses defaults. No `prefer_skills: []`, no `avoid_skills: []`, no `auto_supervisor: {}` — those are just noise.\n\n---\n\n## Models Example\n\n```yaml\n---\nversion: 1\nmodels:\n  research: claude-sonnet-4-6\n  planning: claude-opus-4-6\n  execution: claude-sonnet-4-6\n  completion: claude-sonnet-4-6\n---\n```\n\nOpus for planning (where architectural decisions matter most), Sonnet for everything else (faster, cheaper). Omit any key to use the currently selected model.\n\n## Models with Fallbacks Example\n\n```yaml\n---\nversion: 1\nmodels:\n  research:\n    model: openrouter/deepseek/deepseek-r1\n    fallbacks:\n      - openrouter/minimax/minimax-m2.5\n  planning:\n    model: claude-opus-4-6\n    fallbacks:\n      - openrouter/z-ai/glm-5\n      - openrouter/moonshotai/kimi-k2.5\n  execution:\n    model: openrouter/z-ai/glm-5\n    fallbacks:\n      - openrouter/minimax/minimax-m2.5\n  completion: openrouter/minimax/minimax-m2.5\n---\n```\n\nWhen a model fails to switch (provider unavailable, rate limited, credits exhausted), GSD automatically tries the next model in the `fallbacks` list. This ensures auto-mode continues even when your preferred provider hits limits.\n\n## Provider Targeting\n\nWhen the same model ID exists across multiple providers (e.g., `claude-sonnet-4-6` on both Anthropic and Bedrock), use the `provider/model` format or the `provider` field to target a specific one:\n\n```yaml\n---\nversion: 1\nmodels:\n  # String format: provider/model\n  research: bedrock/claude-sonnet-4-6\n  planning: anthropic/claude-opus-4-6\n\n  # Object format: explicit provider field\n  execution:\n    model: claude-sonnet-4-6\n    provider: bedrock\n    fallbacks:\n      - anthropic/claude-sonnet-4-6\n---\n```\n\nIf you use a bare model ID (no provider prefix) and it exists in multiple providers, GSD will warn you and resolve to the first available match. Use `provider/model` format to avoid ambiguity.\n\n**Cost-optimized example** — use cheap models with expensive ones as fallback for critical phases:\n\n```yaml\n---\nversion: 1\nmodels:\n  research: openrouter/deepseek/deepseek-r1 # $0.28/$0.42 per 1M tokens\n  planning:\n    model: claude-opus-4-6 # $5/$25 — best for architecture\n    fallbacks:\n      - openrouter/z-ai/glm-5 # $1/$3.20 — strong alternative\n  execution: openrouter/minimax/minimax-m2.5 # $0.30/$1.20 — cheapest quality\n  completion: openrouter/minimax/minimax-m2.5\n---\n```\n\n---\n\n## Example Variations\n\n**Minimal — always load a UAT skill and route Clerk tasks:**\n\n```yaml\n---\nversion: 1\nalways_use_skills:\n  - /Users/you/.claude/skills/verify-uat\nskill_rules:\n  - when: finishing implementation and human judgment matters\n    use:\n      - /Users/you/.claude/skills/verify-uat\n---\n```\n\n**Richer routing — prefer cleanup and authentication skills:**\n\n```yaml\n---\nversion: 1\nprefer_skills:\n  - commit-ignore\nskill_rules:\n  - when: task involves Clerk authentication\n    use:\n      - clerk\n      - clerk-setup\n  - when: the user is looking for installable capability rather than implementation\n    prefer:\n      - find-skills\n---\n```\n\n---\n\n## Git Preferences Example\n\n```yaml\n---\nversion: 1\ngit:\n  auto_push: true\n  push_branches: true\n  remote: origin\n  snapshots: true\n  pre_merge_check: auto\n  commit_type: feat\n---\n```\n\nAll git fields are optional. Omit any field to use the default behavior. Project-level preferences override global preferences on a per-field basis.\n\n---\n\n## Budget & Cost Control Example\n\n```yaml\n---\nversion: 1\nbudget_ceiling: 10.00\nbudget_enforcement: pause\ncontext_pause_threshold: 80\n---\n```\n\nSets a $10 budget ceiling. Auto-mode pauses when the ceiling is reached. Context window pauses at 80% usage for checkpointing.\n\n---\n\n## Notifications Example\n\n```yaml\n---\nversion: 1\nnotifications:\n  enabled: true\n  on_complete: false\n  on_error: true\n  on_budget: true\n  on_milestone: true\n  on_attention: true\n---\n```\n\nDisables per-unit completion notifications (noisy in long runs) while keeping error, budget, milestone, and attention notifications enabled.\n\n---\n\n## cmux Example\n\n```yaml\n---\nversion: 1\ncmux:\n  enabled: true\n  notifications: true\n  sidebar: true\n  splits: true\n  browser: false\n---\n```\n\nEnables cmux-aware notifications, sidebar metadata, and visible subagent splits when GSD is running inside a cmux terminal.\n\n---\n\n## Post-Unit Hooks Example\n\n```yaml\n---\nversion: 1\npost_unit_hooks:\n  - name: code-review\n    after:\n      - execute-task\n    prompt: \"Review the code changes in {sliceId}/{taskId} for quality, security, and test coverage.\"\n    max_cycles: 1\n    artifact: REVIEW.md\n---\n```\n\nRuns an automated code review after each task execution. Skips if `REVIEW.md` already exists (idempotent).\n\n---\n\n## Pre-Dispatch Hooks Examples\n\n**Modify — inject instructions before every task:**\n\n```yaml\n---\nversion: 1\npre_dispatch_hooks:\n  - name: enforce-standards\n    before:\n      - execute-task\n    action: modify\n    prepend: \"Follow our TypeScript coding standards and always run linting.\"\n---\n```\n\n**Skip — skip per-slice research when a research file already exists:**\n\n```yaml\n---\nversion: 1\npre_dispatch_hooks:\n  - name: skip-existing-research\n    before:\n      - research-slice\n    action: skip\n    skip_if: RESEARCH.md\n---\n```\n\n**Replace — substitute a custom prompt for task execution:**\n\n```yaml\n---\nversion: 1\npre_dispatch_hooks:\n  - name: tdd-execute\n    before:\n      - execute-task\n    action: replace\n    prompt: \"Implement the task using strict TDD. Write failing tests first, then implement, then refactor.\"\n    model: claude-opus-4-6\n---\n```\n\n---\n\n## Token Profile & Phases Example\n\n```yaml\n---\nversion: 1\ntoken_profile: budget\nphases:\n  skip_research: true\n  skip_reassess: true\n  skip_slice_research: false\n---\n```\n\nUses the `budget` profile to minimize token usage, with explicit override to keep slice-level research enabled.\n\n---\n\n## Remote Questions Example\n\n```yaml\n---\nversion: 1\nremote_questions:\n  channel: slack\n  channel_id: \"C0123456789\"\n  timeout_minutes: 15\n  poll_interval_seconds: 10\n---\n```\n\nRoutes interactive questions to a Slack channel for headless auto-mode sessions. Questions time out after 15 minutes if unanswered.\n\n---\n\n## Dynamic Routing Example\n\n```yaml\n---\nversion: 1\ndynamic_routing:\n  enabled: true\n  tier_models:\n    light: openrouter/minimax/minimax-m2.5\n    standard: claude-sonnet-4-6\n    heavy: claude-opus-4-6\n  escalate_on_failure: true\n  budget_pressure: true\n---\n```\n\nAutomatically selects model tier based on task complexity. Simple tasks use the `light` model, complex tasks escalate to `heavy`. Under budget pressure, tasks are routed to cheaper tiers.\n\n---\n\n## Parallel Execution Example\n\n```yaml\n---\nversion: 1\nparallel:\n  enabled: true\n  max_workers: 3\n  merge_strategy: per-milestone\n  auto_merge: confirm\n---\n```\n\nRuns up to 3 slices concurrently in separate worktrees. Results are merged per-milestone with user confirmation.\n\n---\n\n## Verification Example\n\n```yaml\n---\nversion: 1\nverification_commands:\n  - npm test\n  - npm run lint\n  - npm run typecheck\nverification_auto_fix: true\nverification_max_retries: 2\n---\n```\n\nRuns test, lint, and typecheck after each task. On failure, auto-fix is attempted up to 2 times before reporting the issue.\n\n## Experimental Features Example\n\n```yaml\n---\nversion: 1\nexperimental:\n  rtk: true\n---\n```\n\nOpts in to RTK shell-command compression. RTK is downloaded automatically on first use. Set `GSD_RTK_DISABLED=1` to force-disable at the environment level regardless of this setting.\n","isInternal":false,"tokens":8583,"sizeBytes":35798},{"name":"heal-skill.md","path":"src/resources/extensions/gsd/prompts/heal-skill.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/extensions/gsd/prompts/heal-skill.md","title":"Prompts Skill","category":"anthropic-skill","format":"markdown","content":"## Skill Heal Analysis\n\nAnalyze the just-completed unit ({{unitId}}) for skill drift.\n\n### Steps\n\n1. **Identify loaded skill**: Check which SKILL.md file was read during this unit by examining recent tool calls. If no skill was explicitly loaded (no `read` call to a SKILL.md path), write \"No skill loaded — skipping heal analysis\" to {{healArtifact}} and stop.\n\n2. **Read the skill**: Load the SKILL.md that was used during this unit.\n\n3. **Compare execution to skill guidance**: Review what the agent actually did vs what the skill recommended. Look for:\n   - API patterns the skill recommended that the agent did differently\n   - Error handling approaches the skill specified but the agent bypassed\n   - Conventions the skill documented that the agent ignored\n   - Outdated instructions in the skill that caused errors, retries, or workarounds\n   - Commands or tools the skill referenced that no longer exist or have changed\n\n4. **Assess drift severity**:\n   - **None**: Agent followed skill correctly → write \"No drift detected\" to {{healArtifact}} and stop\n   - **Minor**: Agent found a better approach but skill isn't wrong → append a note to `.gsd/KNOWLEDGE.md` and stop\n   - **Significant**: Skill has outdated or incorrect guidance → continue to step 5\n\n5. **If significant drift found**, append a heal suggestion to `.gsd/skill-review-queue.md`:\n\n```markdown\n### {{skillName}} (flagged {{date}})\n- **Unit:** {{unitId}}\n- **Issue:** {1-2 sentence description of what was wrong}\n- **Root cause:** {outdated API / incorrect pattern / missing context / etc.}\n- **Discovery method:** {how the agent discovered the skill was wrong — error message, trial and error, docs lookup, etc.}\n- **Proposed fix:**\n  - File: {relative path to the file in the skill directory}\n  - Section: {section heading or line range}\n  - Current: {quote the incorrect/outdated text}\n  - Suggested: {the corrected text}\n- **Action:** [ ] Reviewed [ ] Updated [ ] Dismissed\n```\n\nThen write a brief summary of the finding to {{healArtifact}}.\n\n**Critical rules:**\n- Do NOT modify any skill files directly. Only write to the review queue.\n- The SkillsBench research (Feb 2026) shows curated skills beat auto-generated ones by +16.2pp. Human review is what makes this valuable.\n- Keep the analysis focused — don't flag stylistic preferences, only genuine errors or outdated content.\n- If multiple issues found, write one entry per issue.\n","isInternal":false,"tokens":574,"sizeBytes":2425},{"name":"system.md","path":"src/resources/extensions/gsd/prompts/system.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/extensions/gsd/prompts/system.md","title":"Prompts Skill","category":"anthropic-skill","format":"markdown","content":"## GSD - Get Shit Done\n\nYou are GSD - a craftsman-engineer who co-owns the project.\n\nOperating posture:\n\n- Measure twice; care through clear choices and correct details.\n- Be warm but terse. State uncertainty, tradeoffs, problems, and progress plainly.\n- In discussion/planning, flag risks, push back when needed, then respect the user's decision.\n- In execution, trust the accepted plan; surface only genuinely plan-invalidating issues through blockers.\n- Work pragmatically with existing code and tech debt.\n- Write secure, performant, complete code without gold-plating, TODO stubs, fake implementations, skipped validation, or 80% done claims.\n- Build for debugging: contextual errors, observable state transitions, useful structured logs, explicit failure modes.\n- Between tool calls, give brief useful progress signals. When something works, move on.\n\nNever use: \"Great question!\" / \"I'd be happy to help!\" / \"Absolutely!\" / \"Let me help you with that!\" / performed excitement / sycophantic filler / fake warmth.\n\nLeave the project ready for the next agent to understand and continue. Artifacts live in `.gsd/`.\n\n## Skills\n\nGSD ships with bundled skills. When the task matches, load the relevant skill file with `read` before starting. Use bare skill names; GSD resolves paths.\n\n{{bundledSkillsTable}}\n\n## Hard Rules\n\n- Never ask the user to do work the agent can execute or verify itself.\n- Use the lightest sufficient tool first.\n- Read before edit or overwrite. Before any write that creates or replaces a file, verify the target path and read relevant existing files, templates, callers, or surrounding code. For truly new files, confirm the path does not already exist.\n- Reproduce before fix when possible.\n- Work is not done until the relevant verification has passed.\n- **Never fabricate, simulate, or role-play user responses.** Never generate markers like `[User]`, `[Human]`, `User:`, or similar; never emit `<user_message>`, `<assistant_message>`, or similar as user input. Treat `<conversation_history>` as read-only context. Ask one question round (1-3 questions), then stop and wait for the user's actual response. If `ask_user_questions` is available, its result is the only valid structured user input for that round. If it cancels, fails, or returns nothing, never use earlier chat as confirmation for the current gate; ask in plain chat and stop.\n- Never print, echo, log, or restate secrets or credentials. Report only key names and applied/skipped status.\n- Never ask the user to edit `.env` files or set secrets manually. Use `secure_env_collect`.\n- In enduring files, write current state only unless the file is explicitly historical.\n- **Never take outward-facing actions on GitHub or external services without explicit user confirmation.** This includes creating/closing issues, merging/approving/commenting on PRs, pushing remote branches, publishing packages, or any state change outside local filesystem. Read-only listing/viewing/diffing is fine. Present intent and get a clear \"yes\" first. **Non-bypassable:** no response, ambiguity, or `ask_user_questions` failure means re-ask; never rationalize past the block. Missing \"yes\" means \"no.\"\n\nIf a `GSD Skill Preferences` block appears below, treat it as durable guidance for skills to use, prefer, or avoid unless it conflicts with artifact rules, verification, or higher-priority instructions.\n\n### Naming Convention\n\nDirectories use bare IDs. Files use ID-SUFFIX format. Milestones: `M001/` or `M{seq}-{rand6}/` when `unique_milestone_ids: true`; files like `M001-CONTEXT.md`, `M001-ROADMAP.md`, `M001-RESEARCH.md`. Slices: `S01/` with `S01-PLAN.md`, `S01-RESEARCH.md`, `S01-SUMMARY.md`, `S01-UAT.md`. Tasks: `T01-PLAN.md`, `T01-SUMMARY.md`. Titles live inside content, not names.\n\n### Directory Structure\n\n```\n.gsd/\n  PROJECT.md, REQUIREMENTS.md, DECISIONS.md, KNOWLEDGE.md, CODEBASE.md, OVERRIDES.md, QUEUE.md, STATE.md\n  runtime/, activity/, worktrees/\n  milestones/M001/\n    M001-CONTEXT.md, M001-RESEARCH.md, M001-ROADMAP.md, M001-SUMMARY.md\n    slices/S01/\n      S01-CONTEXT.md, S01-RESEARCH.md, S01-PLAN.md, S01-SUMMARY.md, S01-UAT.md\n      tasks/T01-PLAN.md, tasks/T01-SUMMARY.md\n```\n\n`runtime/`, `activity/`, `worktrees/`, and `STATE.md` are system-managed. `PROJECT.md` is current state; `REQUIREMENTS.md` is the active capability contract; `DECISIONS.md` and `KNOWLEDGE.md` are append-only; `CODEBASE.md` is an auto-refreshed codebase map.\n\n### Isolation Model\n\nAuto-mode isolation is configured in `.gsd/PREFERENCES.md` under `git.isolation`: **none** works on the current branch; **worktree** uses `.gsd/worktrees/<MID>/` on `milestone/<MID>` and merges back on completion; **branch** uses `milestone/<MID>` in-place. Slices commit sequentially on the active branch; no per-slice branches.\n\n**If you are executing in auto-mode, your working directory is shown in the Working Directory section of your prompt.** Use relative paths. Do not navigate to any other copy of the project.\n\n### Conventions\n\n- `PROJECT.md`: living current-state doc, refreshed at slice completion when stale.\n- `REQUIREMENTS.md`: capability contract; requirements move Active/Validated/Deferred/Blocked/Out of Scope as evidence changes.\n- `DECISIONS.md` and `KNOWLEDGE.md`: append-only decision/rule registers.\n- `CODEBASE.md`: generated structural cache. GSD auto-refreshes it when tracked files change and injects it when available. Use `/gsd codebase update` only to force refresh.\n- `CONTEXT.md`: milestone/slice scope, goals, constraints, decisions; authoritative when present.\n- Milestones are phases; slices are demoable increments ordered by risk; tasks are single-context units.\n- Checkboxes are toggled by gsd_* tools, never manually.\n- Summaries compress prior work; read them instead of all task details.\n\n### Artifact Templates\n\nTemplates are in `{{templatesDir}}`.\n\n**Always read the relevant template before writing an artifact.** Parsers depend on exact formatting:\n\n- Roadmap slices: `- [ ] **S01: Title** \\`risk:level\\` \\`depends:[]\\``\n- Plan tasks: `- [ ] **T01: Title** \\`est:estimate\\``\n- Summaries use YAML frontmatter\n\n### Commands\n\n- `/gsd` - contextual wizard\n- `/gsd auto` - auto-execute (fresh context per task)\n- `/gsd stop` - stop auto-mode\n- `/gsd status` - progress dashboard overlay\n- `/gsd queue` - queue future milestones (safe while auto-mode is running)\n- `/gsd quick <task>` - quick task with GSD guarantees (atomic commits, state tracking) but no milestone ceremony\n- `/gsd codebase [generate|update|stats]` - manage the `.gsd/CODEBASE.md` cache used for prompt context\n- `{{shortcutDashboard}}` - toggle dashboard overlay\n- `{{shortcutShell}}` - show shell processes\n\n## Execution Heuristics\n\n### Tool rules\n\n**File reading:** Use `read` for file inspection. Never use `cat`, `head`, `tail`, or `sed -n` to view contents. Use `read` with `offset`/`limit` for slicing. `bash` is for searching (`rg`, `grep`, `find`) and commands, not displaying files.\n\n**File editing:** Always `read` before `edit` or overwrite. Before `write`, confirm whether the path exists; if it does, `read` it first and preserve intentional existing content. Use `write` only for new files or complete rewrites.\n\n**Code navigation:** Use `lsp` for definition, type_definition, implementation, references, calls, hover, signature, symbols, rename, code_actions, format, and diagnostics. Do not `grep` symbol definitions or shell out to formatters when `lsp` can do it. After code edits, run `lsp diagnostics`.\n\n**Codebase exploration:** Use `subagent` with `scout` for broad unfamiliar subsystem mapping, `rg` for text search, and `lsp` for structure. Do not read files one-by-one to explore; search first, then read relevant files.\n\n**Documentation lookup:** Use `resolve_library` -> `get_library_docs` for library/framework questions. Start with `tokens=5000`. Never guess API signatures when docs are available.\n\n**External facts:** Use `search-the-web` + `fetch_page`, or `search_and_read`; use `freshness` for recency. Never state current facts from training data without verification.\n\n**Background processes:** Use `bg_shell` `start` + `wait_for_ready` for servers/watchers/daemons. Never use `bash` with `&` or `nohup`; inherited stdout can hang. Never poll with `sleep`; use `wait_for_ready`. For status use `digest`, `highlights` for significant lines, and `output` only when debugging.\n\n**One-shot commands:** Use `async_bash` for builds, tests, and installs. Results are pushed on exit; use `await_job` only to block on a specific job.\n\n**Stale job hygiene:** After editing source to fix a failure, `cancel_job` every in-flight `async_bash` job before rerunning. Changed inputs make in-flight outputs untrusted.\n\n**Secrets:** Use `secure_env_collect`. Never ask the user to edit `.env` files or paste secrets.\n\n**Browser verification:** Verify frontend work against a running app. Discovery: `browser_find`/`browser_snapshot_refs`. Action: refs/selectors -> `browser_batch`. Verification: `browser_assert`. Diagnostics: `browser_diff` -> console/network logs -> full inspection as last resort. Retry only with a new hypothesis.\n\n### Anti-patterns — never do these\n\n- Never use `cat` to read a file you might edit; use `read`.\n- Never `grep` for a function definition when `lsp` go-to-definition is available.\n- Never poll servers with `sleep` loops; use `bg_shell wait_for_ready`.\n- Never background with `bash` + `&`; use `bg_shell start`.\n- Never use `bg_shell output` for status; use `digest`.\n- Never read files one-by-one to understand a subsystem; use `rg` or `scout` first.\n- Never guess library APIs; use `get_library_docs`.\n- Never ask the user to run/check/set something you can do.\n- Never await stale async jobs after editing source; cancel then re-run.\n- Never query `.gsd/gsd.db` directly via `sqlite3`, `better-sqlite3`, or `node -e require('better-sqlite3')`; the engine owns a single-writer WAL connection. Use `gsd_milestone_status`, `gsd_journal_query`, or other `gsd_*` tools.\n\n### Ask vs infer\n\nAsk only when the answer materially affects the result and cannot be derived from repo evidence, docs, runtime behavior, or command output. If multiple interpretations are reasonable, choose the smallest safe reversible action.\n\n### Code structure and abstraction\n\n- Prefer small primitives over monoliths; extract around real seams.\n- Separate orchestration from implementation.\n- Prefer boring standard abstractions over clever custom frameworks.\n- Do not abstract speculatively; keep code local until the seam stabilizes.\n- Preserve local consistency.\n\n### Verification and definition of done\n\nVerify according to task type: bug fix → rerun repro, script fix → rerun command, UI fix → verify in browser, refactor → run tests, env fix → rerun blocked workflow, file ops → confirm filesystem state, docs → verify paths and commands match reality.\n\nFor non-trivial work, verify both the feature and the failure/diagnostic surface. If a command fails, loop: inspect error, fix, rerun until it passes or a real blocker requires user input.\n\nWork is not done when the code compiles. Work is done when the verification passes.\n\n### Agent-First Observability\n\nFor relevant work: add health/status surfaces, persist failure state (last error, phase, timestamp, retry count), verify both happy path and at least one diagnostic signal. Never log secrets. Remove noisy one-off instrumentation before finishing unless it provides durable diagnostic value.\n\n### Root-cause-first debugging\n\nFix root causes, not symptoms. If applying temporary mitigation, label it and preserve the path to the real fix. Never add guards/try-catch to suppress undiagnosed errors.\n\n## Communication\n\n- All plans are for the agent's own execution, not an imaginary team's. No enterprise patterns unless explicitly asked for.\n- Push back on security issues, performance problems, anti-patterns, and unnecessary complexity with concrete reasoning - especially during discussion and planning.\n- Between tool calls, narrate decisions, discoveries, phase transitions, and verification outcomes in one or two complete sentences. Do not narrate every call or the obvious.\n- State uncertainty plainly: \"Not sure this handles X - testing it.\" No performed confidence, no hedging paragraphs.\n- All user-visible narration must be grammatical English. Do not emit compressed planner notes like \"Need inspect X\". If it fits a commit comment or standup note, it is acceptable.\n- When debugging, stay curious. Problems are puzzles. Say what's interesting about the failure before reaching for fixes.\n- After completing a task, give a brief summary and 2-4 numbered next-step options; last option is always \"Other\". Omit the list for strict output formats.\n\nGood narration: \"Three existing handlers follow a middleware pattern - using that instead of a custom wrapper.\"\nGood narration: \"Tests pass. Running slice-level verification.\"\nGood narration: \"I need the task-plan template first, then I'll compare the existing T01 and T02 plans.\"\nBad narration: \"Reading the file now.\" / \"Let me check this.\" / \"I'll look at the tests next.\"\nBad narration: \"Need create plan artifact likely requires template maybe read existing task plans.\"\n","isInternal":false,"tokens":3080,"sizeBytes":13216},{"name":"answer-injection.md","path":"src/resources/extensions/gsd/skills/gsd-headless/references/answer-injection.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/extensions/gsd/skills/gsd-headless/references/answer-injection.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Answer Injection\n\nPre-supply answers to eliminate interactive prompts during headless execution.\n\n## CLI Usage\n\n```bash\ngsd headless --answers answers.json auto\ngsd headless --answers answers.json new-milestone --context spec.md --auto\n```\n\nThe `--answers` flag takes a path to a JSON file containing pre-supplied answers and secrets.\n\n## Answer File Schema\n\n```json\n{\n  \"questions\": {\n    \"question_id\": \"selected_option_label\",\n    \"multi_select_question\": [\"option_a\", \"option_b\"]\n  },\n  \"secrets\": {\n    \"API_KEY\": \"sk-...\",\n    \"DATABASE_URL\": \"postgres://...\"\n  },\n  \"defaults\": {\n    \"strategy\": \"first_option\"\n  }\n}\n```\n\n### Fields\n\n- **questions**: Map question ID → answer. String for single-select, string[] for multi-select.\n- **secrets**: Map env var name → value. Injected as environment variables into the RPC child process. The child's `checkExistingEnvKeys()` detects them in `process.env` and marks them as \"already set\" — no interactive prompt needed.\n- **defaults.strategy**: Fallback for unmatched questions.\n  - `\"first_option\"` — auto-select first available option (default)\n  - `\"cancel\"` — cancel the request\n\n## Secrets Mechanism\n\nSecrets are injected via the `RpcClient` `env` option, which merges them into the child process's `process.env`. This means:\n\n1. The headless orchestrator reads the answer file\n2. Secret values are passed as `env` to `RpcClient`\n3. The child process spawns with these env vars set\n4. When `secure_env_collect` runs, `checkExistingEnvKeys()` finds the keys already in `process.env`\n5. The tool skips the interactive prompt and reports the keys as \"already configured\"\n\nSecrets are never logged or included in event streams.\n\n## How It Works\n\nTwo-phase correlation:\n1. **Observe** `tool_execution_start` events for `ask_user_questions` — extracts question metadata (ID, options, allowMultiple)\n2. **Match** subsequent `extension_ui_request` events to metadata, respond with pre-supplied answer\n\nHandles out-of-order events (extension_ui_request can arrive before tool_execution_start in RPC mode) via deferred processing queue with 500ms timeout.\n\n## Coexistence with --supervised\n\nBoth `--answers` and `--supervised` can be active simultaneously. Priority order:\n1. Answer injector tries first\n2. If no answer found, supervised mode takes over\n3. If no orchestrator response, auto-responder kicks in after timeout\n\n## Without Answer Injection\n\nHeadless mode has built-in auto-responders:\n- **select** → picks first option\n- **confirm** → auto-confirms\n- **input** → empty string\n- **editor** → returns prefill or empty\n\nAnswer injection overrides these defaults with specific answers when precision matters.\n\n## Diagnostics\n\nThe injector tracks stats printed in the summary:\n- `questionsAnswered` / `questionsDefaulted`\n- `secretsProvided`\n\nUnused question IDs and secret keys are warned about at the end.\n","isInternal":false,"tokens":661,"sizeBytes":2884},{"name":"commands.md","path":"src/resources/extensions/gsd/skills/gsd-headless/references/commands.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/extensions/gsd/skills/gsd-headless/references/commands.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# GSD Commands Reference\n\nAll commands can be run via `gsd headless [command]`.\n\n## Workflow Commands\n\n| Command | Description |\n|---------|-------------|\n| `auto` | Autonomous mode — loop until milestone complete (default) |\n| `next` | Step mode — execute one unit, then exit |\n| `stop` | Stop auto-mode gracefully |\n| `pause` | Pause auto-mode (preserves state, resumable) |\n| `new-milestone` | Create milestone from specification (requires `--context`) |\n| `dispatch <phase>` | Force-dispatch: research, plan, execute, complete, reassess, uat, replan |\n| `discuss` | Start guided milestone/slice discussion |\n\n## State Inspection\n\n| Command | Description |\n|---------|-------------|\n| `query` | **Instant JSON snapshot** — state, next dispatch, parallel costs. No LLM, ~50ms. Recommended for orchestrators. |\n| `status` | Progress dashboard (TUI overlay — useful interactively, not for parsing) |\n| `visualize` | Workflow visualizer (deps, metrics, timeline) |\n| `history` | Execution history (supports --cost, --phase, --model, limit) |\n\n## Unit Control\n\n| Command | Description |\n|---------|-------------|\n| `skip` | Prevent a unit from auto-mode dispatch |\n| `undo` | Revert last completed unit (--force flag) |\n| `steer <desc>` | Hard-steer plan documents during execution |\n| `queue` | Queue and reorder future milestones |\n| `capture` | Fire-and-forget thought capture |\n| `triage` | Manually trigger triage of pending captures |\n\n## Configuration & Health\n\n| Command | Description |\n|---------|-------------|\n| `prefs` | Manage preferences (global/project/status/wizard/setup) |\n| `config` | Set API keys for external tools |\n| `doctor` | Runtime health checks with auto-fix |\n| `hooks` | Show configured post-unit and pre-dispatch hooks |\n| `knowledge <rule\\|pattern\\|lesson>` | Add persistent project knowledge |\n| `cleanup` | Remove merged branches or snapshots |\n| `export` | Export results (--json, --markdown) |\n| `migrate` | Migrate v1 .planning directory to DB-backed .gsd with backup and audit |\n| `remote` | Control remote auto-mode (slack, discord, status, disconnect) |\n| `inspect` | Show SQLite DB diagnostics (schema, row counts) |\n| `forensics` | Post-mortem investigation of auto-mode failures |\n\n## Phases\n\nGSD workflows progress through these phases:\n`pre-planning` → `needs-discussion` → `discussing` → `researching` → `planning` → `executing` → `verifying` → `summarizing` → `advancing` → `validating-milestone` → `completing-milestone` → `complete`\n\nSpecial phases: `paused`, `blocked`, `replanning-slice`\n\n## Hierarchy\n\n- **Milestone**: Shippable version (4-10 slices, 1-4 weeks)\n- **Slice**: One demoable vertical capability (1-7 tasks, 1-3 days)\n- **Task**: One context-window-sized unit of work (one session)\n","isInternal":false,"tokens":700,"sizeBytes":2774},{"name":"multi-session.md","path":"src/resources/extensions/gsd/skills/gsd-headless/references/multi-session.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/extensions/gsd/skills/gsd-headless/references/multi-session.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Multi-Session Orchestration\n\nHow to run and monitor multiple concurrent GSD sessions.\n\n## Architecture\n\nGSD uses **file-based IPC** — no sockets or ports. All coordination happens through JSON files in `.gsd/parallel/`.\n\n```\n.gsd/parallel/\n├── M001.status.json    # Worker heartbeat + state\n├── M001.signal.json    # Coordinator → worker commands (ephemeral)\n├── M002.status.json\n├── M003.status.json\n└── ...\n```\n\n## Worker Isolation\n\nEach worker gets:\n1. **`GSD_MILESTONE_LOCK=M00X`** — state derivation only sees this milestone\n2. **`GSD_PARALLEL_WORKER=1`** — prevents nested parallel spawns\n3. **Own git worktree** at `.gsd/worktrees/M00X/` — branch `milestone/M00X`\n\nWorkers cannot interfere with each other. Each has its own filesystem and git branch.\n\n## Status File Schema\n\nWritten atomically (`.tmp` + rename) by each worker at `.gsd/parallel/<milestoneId>.status.json`:\n\n```json\n{\n  \"milestoneId\": \"M001\",\n  \"pid\": 12345,\n  \"state\": \"running\",\n  \"currentUnit\": {\n    \"type\": \"task\",\n    \"id\": \"T03\",\n    \"startedAt\": 1710000000000\n  },\n  \"completedUnits\": 7,\n  \"cost\": 1.23,\n  \"lastHeartbeat\": 1710000015000,\n  \"startedAt\": 1710000000000,\n  \"worktreePath\": \".gsd/worktrees/M001\"\n}\n```\n\n**States:** `running`, `paused`, `stopped`, `error`\n\n## Signal Files\n\nCoordinator writes to `.gsd/parallel/<milestoneId>.signal.json`. Worker consumes and deletes on next dispatch cycle.\n\n```json\n{\n  \"signal\": \"pause\",\n  \"sentAt\": 1710000020000,\n  \"from\": \"coordinator\"\n}\n```\n\n**Signals:** `pause`, `resume`, `stop`, `rebase`\n\n## Spawning Workers\n\n```bash\n# Spawn worker in its worktree\nGSD_MILESTONE_LOCK=M001 \\\nGSD_PARALLEL_WORKER=1 \\\n  gsd headless --json auto 2>logs/M001.log &\nWORKER_PID=$!\n```\n\nWorkers emit JSONL events on stdout when `--json` is set.\n\n## Monitoring All Workers\n\n```bash\n# Dashboard: enumerate all status files\nfor f in .gsd/parallel/*.status.json; do\n  [ -f \"$f\" ] || continue\n  jq -r '[.milestoneId, .state, (.currentUnit.id // \"idle\"), \"\\(.cost | tostring)$\"] | join(\"\\t\")' \"$f\"\ndone\n\n# Liveness check\nfor f in .gsd/parallel/*.status.json; do\n  PID=$(jq -r '.pid' \"$f\")\n  MID=$(jq -r '.milestoneId' \"$f\")\n  if kill -0 \"$PID\" 2>/dev/null; then\n    echo \"$MID: alive (pid=$PID)\"\n  else\n    echo \"$MID: DEAD (pid=$PID) — cleanup needed\"\n    rm \"$f\"\n  fi\ndone\n```\n\n## Sending Commands\n\n```bash\n# Pause a worker\nsend_signal() {\n  local MID=$1 SIGNAL=$2\n  echo \"{\\\"signal\\\":\\\"$SIGNAL\\\",\\\"sentAt\\\":$(date +%s000),\\\"from\\\":\\\"coordinator\\\"}\" \\\n    > \".gsd/parallel/${MID}.signal.json\"\n}\n\nsend_signal M001 pause\nsend_signal M002 stop\nsend_signal M003 resume\n```\n\n## Budget Enforcement\n\nUse `gsd headless query` for instant aggregate cost:\n```bash\nTOTAL=$(gsd headless query | jq -r '.cost.total')\nCEILING=50.00\nif (( $(echo \"$TOTAL > $CEILING\" | bc -l) )); then\n  echo \"Budget exceeded ($TOTAL > $CEILING) — stopping all\"\n  for f in .gsd/parallel/*.status.json; do\n    MID=$(jq -r '.milestoneId' \"$f\")\n    send_signal \"$MID\" stop\n  done\nfi\n```\n\n## Stale Session Cleanup\n\nA session is stale when:\n- PID is dead (`kill -0 $pid` fails), OR\n- `lastHeartbeat` is older than 30 seconds\n\n```bash\nNOW=$(date +%s000)\nSTALE_THRESHOLD=30000\nfor f in .gsd/parallel/*.status.json; do\n  PID=$(jq -r '.pid' \"$f\")\n  HB=$(jq -r '.lastHeartbeat' \"$f\")\n  AGE=$((NOW - HB))\n  if ! kill -0 \"$PID\" 2>/dev/null || [ \"$AGE\" -gt \"$STALE_THRESHOLD\" ]; then\n    echo \"Stale: $(jq -r '.milestoneId' \"$f\") — removing\"\n    rm \"$f\"\n  fi\ndone\n```\n\n## Multi-Project Orchestration\n\nWithin one project, milestones are tracked automatically in `.gsd/parallel/`. For orchestrating across **multiple projects**, maintain an external registry:\n\n```json\n{\n  \"sessions\": [\n    { \"project\": \"/path/to/project-a\", \"milestoneId\": \"M001\" },\n    { \"project\": \"/path/to/project-b\", \"milestoneId\": \"M001\" },\n    { \"project\": \"/path/to/project-b\", \"milestoneId\": \"M002\" }\n  ]\n}\n```\n\nThen poll each project's `.gsd/parallel/` directory. GSD has no cross-project awareness — the orchestrator must bridge this gap.\n\n## Built-in Parallel Commands\n\nInside an interactive GSD session, these commands manage the parallel orchestrator:\n\n| Command | Description |\n|---------|-------------|\n| `/gsd parallel start` | Analyze eligibility, spawn workers |\n| `/gsd parallel status` | Show all workers, costs, progress |\n| `/gsd parallel stop [MID]` | Stop one or all workers |\n| `/gsd parallel pause [MID]` | Pause without killing |\n| `/gsd parallel resume [MID]` | Resume paused worker |\n| `/gsd parallel merge [MID]` | Merge completed milestone branch |\n","isInternal":false,"tokens":1360,"sizeBytes":4557},{"name":"SKILL.md","path":"src/resources/extensions/gsd/skills/gsd-headless/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/extensions/gsd/skills/gsd-headless/SKILL.md","title":"gsd-headless","category":"anthropic-skill","format":"markdown","content":"---\nname: gsd-headless\ndescription: Orchestrate GSD (Get Shit Done) projects programmatically via headless CLI. Use when an agent needs to create milestones from specs, execute software development workflows, monitor task progress, check project status, or control GSD execution (pause/stop/skip/steer). Triggers on requests to \"run gsd\", \"create milestone\", \"execute project\", \"check gsd status\", \"orchestrate development\", \"run headless workflow\", or any programmatic interaction with the GSD project management system. Essential for building orchestrators that coordinate multiple GSD workers.\n---\n\n# GSD Headless Orchestration\n\nRun GSD commands without TUI via `gsd headless`. Spawns an RPC child process, auto-responds to UI prompts, streams progress.\n\n## Command Syntax\n\n```bash\ngsd headless [flags] [command] [args...]\n```\n\n**Flags:**\n- `--timeout N` — overall timeout in ms (default 300000)\n- `--json` — JSONL event stream to stdout\n- `--model ID` — override LLM model\n- `--verbose` — show tool calls in progress output\n- `--supervised` — forward interactive UI requests to orchestrator via stdout/stdin\n- `--response-timeout N` — timeout for orchestrator response in supervised mode (default 30000)\n- `--max-restarts N` — auto-restart on crash with backoff (default 3, 0 to disable)\n- `--answers <path>` — pre-supply answers and secrets from JSON file\n- `--events <types>` — filter JSONL output to specific event types (comma-separated, implies `--json`)\n\n**Exit codes:** 0=complete, 1=error/timeout, 2=blocked\n\n## Core Workflows\n\n### 1. Create + Execute a Milestone (end-to-end)\n\n```bash\ngsd headless new-milestone --context spec.md --auto\n```\n\nReads spec, bootstraps `.gsd/`, creates milestone, then chains into auto-mode executing all phases (discuss → research → plan → execute → summarize → complete).\n\nExtra flags for `new-milestone`: `--context <path>` (use `-` for stdin), `--context-text <text>`, `--auto`.\n\n### 2. Run All Queued Work\n\n```bash\ngsd headless auto\n```\n\nDefault command. Loops through all pending units until milestone complete or blocked.\n\n### 3. Run One Unit\n\n```bash\ngsd headless next\n```\n\nExecute exactly one unit (task/slice/milestone step), then exit. Ideal for step-by-step orchestration with external decision logic between steps.\n\n### 4. Instant State Snapshot (no LLM)\n\n```bash\ngsd headless query\n```\n\nReturns a single JSON object with the full project snapshot — no LLM session, instant (~50ms). **This is the recommended way for orchestrators to inspect state.**\n\n```json\n{\n  \"state\": { \"phase\": \"executing\", \"activeMilestone\": {...}, \"activeSlice\": {...}, \"progress\": {...}, \"registry\": [...] },\n  \"next\":  { \"action\": \"dispatch\", \"unitType\": \"execute-task\", \"unitId\": \"M001/S01/T01\" },\n  \"cost\":  { \"workers\": [{ \"milestoneId\": \"M001\", \"cost\": 1.50, ... }], \"total\": 1.50 }\n}\n```\n\n```bash\n# What phase is the project in?\ngsd headless query | jq '.state.phase'\n\n# What would auto-mode do next?\ngsd headless query | jq '.next'\n\n# Total spend across parallel workers\ngsd headless query | jq '.cost.total'\n```\n\n### 5. Dispatch Specific Phase\n\n```bash\ngsd headless dispatch research|plan|execute|complete|reassess|uat|replan\n```\n\nForce-route to a specific phase, bypassing normal state-machine routing.\n\n## Orchestrator Patterns\n\n### Poll-and-React Loop\n\n```bash\n# Instant state check — no LLM cost\nPHASE=$(gsd headless query | jq -r '.state.phase')\nNEXT_ACTION=$(gsd headless query | jq -r '.next.action')\n\ncase \"$PHASE\" in\n  complete) echo \"Done\" ;;\n  blocked)  echo \"Needs intervention\" ;;\n  *)        [ \"$NEXT_ACTION\" = \"dispatch\" ] && gsd headless next ;;\nesac\n```\n\n### Step-by-Step with Monitoring\n\n```bash\nwhile true; do\n  gsd headless next\n  EXIT=$?\n  [ $EXIT -ne 0 ] && break\n  # Instant progress check between steps\n  gsd headless query | jq '{phase: .state.phase, progress: .state.progress}'\ndone\n```\n\n### Multi-Session Orchestration\n\nGSD tracks concurrent workers via file-based IPC in `.gsd/parallel/`. See [references/multi-session.md](references/multi-session.md) for the full architecture.\n\n**Quick overview:**\n\nEach worker spawns with `GSD_MILESTONE_LOCK=M00X` + its own git worktree. Workers write heartbeats to `.gsd/parallel/<milestoneId>.status.json`. The orchestrator enumerates all status files to get a dashboard of all workers, and sends commands via signal files.\n\n```bash\n# Spawn a worker for milestone M001 in its worktree\nGSD_MILESTONE_LOCK=M001 GSD_PARALLEL_WORKER=1 \\\n  gsd headless --json auto \\\n  --cwd .gsd/worktrees/M001 2>worker-M001.log &\n\n# Monitor all workers: read .gsd/parallel/*.status.json\nfor f in .gsd/parallel/*.status.json; do\n  jq '{mid: .milestoneId, state: .state, unit: .currentUnit.id, cost: .cost}' \"$f\"\ndone\n\n# Send pause signal to M001\necho '{\"signal\":\"pause\",\"sentAt\":'$(date +%s000)',\"from\":\"coordinator\"}' \\\n  > .gsd/parallel/M001.signal.json\n```\n\n**Status file fields:** `milestoneId`, `pid`, `state` (running/paused/stopped/error), `currentUnit`, `completedUnits`, `cost`, `lastHeartbeat`, `startedAt`, `worktreePath`.\n\n**Signal commands:** `pause`, `resume`, `stop`, `rebase`.\n\n**Liveness detection:** PID alive check (`kill -0 $pid`) + heartbeat freshness (30s timeout). Stale sessions are auto-cleaned.\n\n**For multiple projects:** each project has its own `.gsd/` directory. The orchestrator must track `(projectPath, milestoneId)` tuples externally.\n\n### JSONL Event Stream\n\nUse `--json` to get real-time events on stdout for downstream processing:\n\n```bash\ngsd headless --json auto 2>/dev/null | while read -r line; do\n  TYPE=$(echo \"$line\" | jq -r '.type')\n  case \"$TYPE\" in\n    tool_execution_start) echo \"Tool: $(echo \"$line\" | jq -r '.toolName')\" ;;\n    extension_ui_request) echo \"GSD: $(echo \"$line\" | jq -r '.message // .title // empty')\" ;;\n    agent_end) echo \"Session ended\" ;;\n  esac\ndone\n```\n\nEvent types: `agent_start`, `agent_end`, `tool_execution_start`, `tool_execution_end`, `extension_ui_request`, `message_update`, `error`.\n\n### Filtered Event Stream\n\nUse `--events` to receive only specific event types — reduces noise for orchestrators:\n\n```bash\n# Only phase-relevant events\ngsd headless --events agent_end,extension_ui_request auto 2>/dev/null\n\n# Only tool execution events\ngsd headless --events tool_execution_start,tool_execution_end auto\n```\n\nThe filter applies only to stdout output. Internal processing (completion detection, supervised mode, answer injection) is unaffected — all events are still processed internally.\n\nAvailable event types: `agent_start`, `agent_end`, `tool_execution_start`, `tool_execution_end`, `tool_execution_update`, `extension_ui_request`, `message_start`, `message_end`, `message_update`, `turn_start`, `turn_end`.\n\n## Answer Injection\n\nPre-supply answers and secrets for headless runs via `--answers`:\n\n```bash\ngsd headless --answers answers.json auto\n```\n\nAnswer file schema:\n```json\n{\n  \"questions\": { \"question_id\": \"selected_option\" },\n  \"secrets\": { \"API_KEY\": \"sk-...\" },\n  \"defaults\": { \"strategy\": \"first_option\" }\n}\n```\n\n- **questions** — question ID → answer (string or string[])\n- **secrets** — env var → value, injected into child process env\n- **defaults.strategy** — `\"first_option\"` (default) or `\"cancel\"` for unmatched\n\nSee [references/answer-injection.md](references/answer-injection.md) for full details.\n\n## GSD Project Structure\n\nAll state lives in `.gsd/` as markdown files (version-controllable):\n\n```\n.gsd/\n  milestones/M001/\n    M001-CONTEXT.md      # Requirements, scope, decisions\n    M001-ROADMAP.md      # Slices with tasks, dependencies, checkboxes\n    M001-SUMMARY.md      # Completion summary\n    slices/S01/\n      S01-PLAN.md        # Task list\n      S01-SUMMARY.md     # Slice summary with frontmatter\n      tasks/T01-PLAN.md  # Individual task spec\n```\n\nState is derived from files on disk — checkboxes in ROADMAP.md are the source of truth for completion.\n\n## All Headless Commands\n\nQuick reference — see [references/commands.md](references/commands.md) for the complete list.\n\n| Command | Purpose |\n|---------|---------|\n| `auto` | Run all queued units (default) |\n| `next` | Run one unit |\n| `query` | Instant JSON snapshot — state, next dispatch, costs (no LLM) |\n| `new-milestone` | Create milestone from spec |\n| `queue` | Queue/reorder milestones |\n| `history` | View execution history |\n| `stop` / `pause` | Control auto-mode |\n| `dispatch <phase>` | Force specific phase |\n| `skip` / `undo` | Unit control |\n| `doctor` | Health check + auto-fix |\n| `steer <desc>` | Hard-steer plan mid-execution |\n","frontmatter":{"name":"gsd-headless","description":"Orchestrate GSD (Get Shit Done) projects programmatically via headless CLI. Use when an agent needs to create milestones from specs, execute software development workflows, monitor task progress, check project status, or control GSD execution (pause/stop/skip/steer). Triggers on requests to \"run gsd\", \"create milestone\", \"execute project\", \"check gsd status\", \"orchestrate development\", \"run headless workflow\", or any programmatic interaction with the GSD project management system. Essential for building orchestrators that coordinate multiple GSD workers."},"isInternal":false,"tokens":2253,"sizeBytes":8555},{"name":"milestone-summary.md","path":"src/resources/extensions/gsd/templates/milestone-summary.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/extensions/gsd/templates/milestone-summary.md","title":"Templates Skill","category":"anthropic-skill","format":"markdown","content":"---\nid: {{milestoneId}}\nprovides:\n  - {{whatThisMilestoneProvides}}\nkey_decisions:\n  - {{decision}}\npatterns_established:\n  - {{pattern}}\nobservability_surfaces:\n  - {{status endpoint, structured log, persisted failure state, diagnostic command, or none}}\nrequirement_outcomes:\n  - id: {{requirementId}}\n    from_status: {{active|blocked|deferred}}\n    to_status: {{validated|deferred|blocked|out_of_scope}}\n    proof: {{whatEvidenceSupportsThisTransition}}\nduration: {{duration}}\nverification_result: passed\ncompleted_at: {{date}}\n---\n\n# {{milestoneId}}: {{milestoneTitle}}\n\n<!-- One-liner must say what the milestone actually delivered, not just that it completed.\n     Good: \"State machine integrity with completing-milestone gating, doctor audits, and observability validation\"\n     Bad: \"Milestone 2 completed\" -->\n\n**{{oneLiner}}**\n\n## What Happened\n\n<!-- Cross-slice narrative: compress all slice summaries into a coherent story.\n     Focus on what was built, how the slices connected, and what the milestone\n     achieved as a whole — not a task-by-task replay. -->\n\n{{crossSliceNarrative}}\n\n## Cross-Slice Verification\n\n<!-- How were the milestone's success criteria verified?\n     Reference specific tests, commands, browser checks, or observable behaviors.\n     Each success criterion from the roadmap should have a corresponding verification entry. -->\n\n{{howSuccessCriteriaWereVerified}}\n\n## Requirement Changes\n\n<!-- Transitions with evidence. Each requirement that changed status during this milestone\n     should be listed with the proof that supports the transition. -->\n\n- {{requirementId}}: {{fromStatus}} → {{toStatus}} — {{evidence}}\n\n## Decision Re-evaluation\n\n<!-- Review decisions from this milestone. OMIT if no decisions need re-evaluation. -->\n\n| Decision | Original Rationale | Still Valid? | Action |\n|----------|-------------------|-------------|--------|\n| {{decisionId}} | {{originalRationale}} | {{yes/no/partially}} | {{keep/revise/supersede}} |\n\n## Forward Intelligence\n\n<!-- Write what you wish you'd known at the start of this milestone.\n     This section is read by the next milestone's planning and research steps.\n     Be specific and concrete — this is the most valuable context you can transfer. -->\n\n### What the next milestone should know\n- {{insightThatWouldHelpDownstreamWork}}\n\n### What's fragile\n- {{fragileAreaOrThinImplementation}} — {{whyItMatters}}\n\n### Authoritative diagnostics\n- {{whereAFutureAgentShouldLookFirst}} — {{whyThisSignalIsTrustworthy}}\n\n### What assumptions changed\n- {{originalAssumption}} — {{whatActuallyHappened}}\n\n## Files Created/Modified\n\n- `{{filePath}}` — {{description}}\n- `{{filePath}}` — {{description}}\n","frontmatter":{"id":{"{ milestoneId }":null},"provides":[{"{ whatThisMilestoneProvides }":null}],"key_decisions":[{"{ decision }":null}],"patterns_established":[{"{ pattern }":null}],"observability_surfaces":[{"{\n  status endpoint,\n  structured log,\n  persisted failure state,\n  diagnostic command,\n  or none\n}":null}],"requirement_outcomes":[{"id":{"{ requirementId }":null},"from_status":{"{ active|blocked|deferred }":null},"to_status":{"{ validated|deferred|blocked|out_of_scope }":null},"proof":{"{ whatEvidenceSupportsThisTransition }":null}}],"duration":{"{ duration }":null},"verification_result":"passed","completed_at":{"{ date }":null}},"isInternal":false,"tokens":601,"sizeBytes":2702},{"name":"slice-summary.md","path":"src/resources/extensions/gsd/templates/slice-summary.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/extensions/gsd/templates/slice-summary.md","title":"Templates Skill","category":"anthropic-skill","format":"markdown","content":"---\nid: {{sliceId}}\nparent: {{milestoneId}}\nmilestone: {{milestoneId}}\nprovides:\n  - {{whatThisSliceProvides}}\nrequires:\n  - slice: {{depSliceId}}\n    provides: {{whatWasConsumed}}\naffects:\n  - {{downstreamSliceId}}\nkey_files:\n  - {{filePath}}\nkey_decisions:\n  - {{decision}}\npatterns_established:\n  - {{pattern}}\nobservability_surfaces:\n  - {{status endpoint, structured log, persisted failure state, diagnostic command, or none}}\ndrill_down_paths:\n  - {{pathToTaskSummary}}\nduration: {{duration}}\nverification_result: passed\ncompleted_at: {{date}}\n---\n\n# {{sliceId}}: {{sliceTitle}}\n\n<!-- One-liner must say what actually shipped, not just that work completed.\n     Good: \"Structured job status endpoint with persisted failure diagnostics\"\n     Bad: \"Status feature implemented\" -->\n\n**{{oneLiner}}**\n\n## What Happened\n\n{{narrative — compress task summaries into a coherent story}}\n\n## Verification\n\n{{whatWasVerifiedAcrossAllTasks — tests, builds, manual checks}}\n\n<!-- If the project has no REQUIREMENTS.md, omit all four requirement sections below entirely — do not fill them with \"none\". These sections only apply when requirements are being actively tracked. -->\n## Requirements Advanced\n\n- {{requirementId}} — {{howThisSliceAdvancedIt}}\n\n## Requirements Validated\n\n- {{requirementId}} — {{whatProofNowMakesItValidated}}\n\n## New Requirements Surfaced\n\n- {{newRequirementOr_none}}\n\n## Requirements Invalidated or Re-scoped\n\n- {{requirementIdOr_none}} — {{what changed}}\n\n## Operational Readiness\n\n<!-- Q8: How will ops know it's healthy/broken? OMIT ENTIRELY for simple slices with no runtime concerns. -->\n\n- **Health signal**: {{howToConfirmHealthy — health endpoint, heartbeat log, metric, or N/A}}\n- **Failure signal**: {{howToDetectBroken — error rate spike, alert, log pattern, or N/A}}\n- **Recovery**: {{selfRecoverOrRestart — auto-reconnect, circuit breaker, manual restart, or N/A}}\n- **Monitoring gaps**: {{silentFailureModes — background jobs, cache eviction, memory pressure, or none}}\n\n## Deviations\n\n<!-- Deviations are unplanned changes to the written plan, not ordinary debugging inside the plan's intended scope. -->\n\n{{deviationsFromPlan_OR_none}}\n\n## Known Limitations\n\n<!-- Known limitations are real gaps, rough edges, or deferred constraints that still exist after this slice shipped. -->\n\n{{whatDoesntWorkYet_OR_whatWasDeferredToLaterSlices}}\n\n## Follow-ups\n\n<!-- Follow-ups are concrete next actions discovered during execution, not a restatement of known limitations. -->\n\n{{workDeferredOrDiscoveredDuringExecution_OR_none}}\n\n## Files Created/Modified\n\n- `{{filePath}}` — {{description}}\n- `{{filePath}}` — {{description}}\n\n## Forward Intelligence\n\n<!-- Write what you wish you'd known at the start of this slice.\n     This section is read by the next slice's planning and research steps.\n     Be specific and concrete — this is the most valuable context you can transfer. -->\n\n### What the next slice should know\n- {{insightThatWouldHelpDownstreamWork}}\n\n### What's fragile\n- {{fragileAreaOrThinImplementation}} — {{whyItMatters}}\n\n### Authoritative diagnostics\n- {{whereAFutureAgentShouldLookFirst}} — {{whyThisSignalIsTrustworthy}}\n\n### What assumptions changed\n- {{originalAssumption}} — {{whatActuallyHappened}}\n","frontmatter":{"id":{"{ sliceId }":null},"parent":{"{ milestoneId }":null},"milestone":{"{ milestoneId }":null},"provides":[{"{ whatThisSliceProvides }":null}],"requires":[{"slice":{"{ depSliceId }":null},"provides":{"{ whatWasConsumed }":null}}],"affects":[{"{ downstreamSliceId }":null}],"key_files":[{"{ filePath }":null}],"key_decisions":[{"{ decision }":null}],"patterns_established":[{"{ pattern }":null}],"observability_surfaces":[{"{\n  status endpoint,\n  structured log,\n  persisted failure state,\n  diagnostic command,\n  or none\n}":null}],"drill_down_paths":[{"{ pathToTaskSummary }":null}],"duration":{"{ duration }":null},"verification_result":"passed","completed_at":{"{ date }":null}},"isInternal":false,"tokens":748,"sizeBytes":3280},{"name":"task-summary.md","path":"src/resources/extensions/gsd/templates/task-summary.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/extensions/gsd/templates/task-summary.md","title":"Templates Skill","category":"anthropic-skill","format":"markdown","content":"---\nid: {{taskId}}\nparent: {{sliceId}}\nmilestone: {{milestoneId}}\nprovides:\n  - {{whatThisTaskProvides}}\nkey_files:\n  - {{filePath}}\nkey_decisions:\n  - {{decision}}\npatterns_established:\n  - {{pattern}}\nobservability_surfaces:\n  - {{status endpoint, structured log, persisted failure state, diagnostic command, or none}}\nduration: {{duration}}\nverification_result: passed\ncompleted_at: {{date}}\n# Set blocker_discovered: true only if execution revealed the remaining slice plan\n# is fundamentally invalid (wrong API, missing capability, architectural mismatch).\n# Do NOT set true for ordinary bugs, minor deviations, or fixable issues.\nblocker_discovered: false\n---\n\n# {{taskId}}: {{taskTitle}}\n\n<!-- One-liner must say what actually shipped, not just that work completed.\n     Good: \"Added retry-aware worker status logging\"\n     Bad: \"Implemented logging improvements\" -->\n\n**{{oneLiner}}**\n\n## What Happened\n\n{{narrative}}\n\n## Verification\n\n{{whatWasVerifiedAndHow — commands run, tests passed, behavior confirmed}}\n\n## Verification Evidence\n\n<!-- Populated from verification gate output. If the gate ran, fill in the table below.\n     If no gate ran (e.g., no verification commands discovered), note that. -->\n\n| # | Command | Exit Code | Verdict | Duration |\n|---|---------|-----------|---------|----------|\n| {{row}} | {{command}} | {{exitCode}} | {{verdict}} | {{duration}} |\n\n## Diagnostics\n\n{{howToInspectWhatThisTaskBuiltLater — status surfaces, logs, error shapes, failure artifacts, or none}}\n\n## Deviations\n\n<!-- Deviations are unplanned changes to the written task plan, not ordinary debugging during implementation. -->\n\n{{deviationsFromPlan_OR_none}}\n\n## Known Issues\n\n{{issuesDiscoveredButNotFixed_OR_none}}\n\n## Files Created/Modified\n\n- `{{filePath}}` — {{description}}\n- `{{filePath}}` — {{description}}\n","frontmatter":{"id":{"{ taskId }":null},"parent":{"{ sliceId }":null},"milestone":{"{ milestoneId }":null},"provides":[{"{ whatThisTaskProvides }":null}],"key_files":[{"{ filePath }":null}],"key_decisions":[{"{ decision }":null}],"patterns_established":[{"{ pattern }":null}],"observability_surfaces":[{"{\n  status endpoint,\n  structured log,\n  persisted failure state,\n  diagnostic command,\n  or none\n}":null}],"duration":{"{ duration }":null},"verification_result":"passed","completed_at":{"{ date }":null},"blocker_discovered":false},"isInternal":false,"tokens":422,"sizeBytes":1831},{"name":"WCAG.md","path":"src/resources/skills/accessibility/references/WCAG.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/accessibility/references/WCAG.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# WCAG 2.1 Quick Reference\n\n## Success criteria by level\n\n### Level A (minimum)\n\n| Criterion | Description |\n|-----------|-------------|\n| **1.1.1** Non-text Content | All images, icons have text alternatives |\n| **1.2.1** Audio-only/Video-only | Provide transcript or audio description |\n| **1.2.2** Captions | Video with audio has captions |\n| **1.2.3** Audio Description | Video has audio description |\n| **1.3.1** Info and Relationships | Information conveyed through presentation is available programmatically |\n| **1.3.2** Meaningful Sequence | Reading order is logical |\n| **1.3.3** Sensory Characteristics | Instructions don't rely solely on shape, color, size, location, orientation, or sound |\n| **1.4.1** Use of Color | Color is not the only visual means of conveying information |\n| **1.4.2** Audio Control | Audio playing automatically can be paused/stopped |\n| **2.1.1** Keyboard | All functionality available via keyboard |\n| **2.1.2** No Keyboard Trap | Keyboard focus can be moved away from any component |\n| **2.1.4** Character Key Shortcuts | Single-key shortcuts can be turned off or remapped |\n| **2.2.1** Timing Adjustable | Time limits can be extended |\n| **2.2.2** Pause, Stop, Hide | Moving/blinking content can be paused |\n| **2.3.1** Three Flashes | Nothing flashes more than 3 times per second |\n| **2.4.1** Bypass Blocks | Skip link or landmark navigation available |\n| **2.4.2** Page Titled | Pages have descriptive titles |\n| **2.4.3** Focus Order | Focus order preserves meaning |\n| **2.4.4** Link Purpose | Link purpose clear from link text or context |\n| **2.5.1** Pointer Gestures | Multi-point gestures have single-pointer alternatives |\n| **2.5.2** Pointer Cancellation | Down-event doesn't trigger action (use up-event or click) |\n| **2.5.3** Label in Name | Accessible name contains visible label text |\n| **2.5.4** Motion Actuation | Motion-triggered functions have alternatives |\n| **3.1.1** Language of Page | Default language specified in HTML |\n| **3.2.1** On Focus | Focus doesn't trigger unexpected changes |\n| **3.2.2** On Input | Input doesn't trigger unexpected changes |\n| **3.3.1** Error Identification | Input errors clearly described |\n| **3.3.2** Labels or Instructions | Form inputs have labels or instructions |\n| **4.1.1** Parsing | HTML is well-formed (no duplicate IDs, proper nesting) |\n| **4.1.2** Name, Role, Value | UI components have accessible names and correct roles |\n\n### Level AA (standard)\n\n| Criterion | Description |\n|-----------|-------------|\n| **1.2.4** Captions (Live) | Live audio has captions |\n| **1.2.5** Audio Description | Pre-recorded video has audio description |\n| **1.3.4** Orientation | Content doesn't restrict orientation |\n| **1.3.5** Identify Input Purpose | Input purpose can be programmatically determined |\n| **1.4.3** Contrast (Minimum) | 4.5:1 for normal text, 3:1 for large text |\n| **1.4.4** Resize Text | Text can be resized to 200% without loss of functionality |\n| **1.4.5** Images of Text | Text used instead of images of text |\n| **1.4.10** Reflow | Content reflows at 320px width without horizontal scroll |\n| **1.4.11** Non-text Contrast | UI components have 3:1 contrast |\n| **1.4.12** Text Spacing | Content adapts to text spacing changes |\n| **1.4.13** Content on Hover/Focus | Additional content is dismissible, hoverable, persistent |\n| **2.4.5** Multiple Ways | Multiple ways to find pages |\n| **2.4.6** Headings and Labels | Headings and labels are descriptive |\n| **2.4.7** Focus Visible | Focus indicator is visible |\n| **3.1.2** Language of Parts | Language changes are marked |\n| **3.2.3** Consistent Navigation | Navigation is consistent across pages |\n| **3.2.4** Consistent Identification | Same functionality uses same labels |\n| **3.3.3** Error Suggestion | Error corrections suggested when known |\n| **3.3.4** Error Prevention (Legal) | Actions can be reversed or confirmed |\n| **4.1.3** Status Messages | Status messages announced to screen readers |\n\n### Level AAA (enhanced)\n\n| Criterion | Description |\n|-----------|-------------|\n| **1.4.6** Contrast (Enhanced) | 7:1 for normal text, 4.5:1 for large text |\n| **1.4.8** Visual Presentation | Foreground/background colors can be selected |\n| **1.4.9** Images of Text (No Exception) | No images of text |\n| **2.1.3** Keyboard (No Exception) | All functionality keyboard accessible |\n| **2.2.3** No Timing | No time limits |\n| **2.2.4** Interruptions | Interruptions can be postponed |\n| **2.2.5** Re-authenticating | Data preserved on re-authentication |\n| **2.2.6** Timeouts | Users warned about data loss from inactivity |\n| **2.3.2** Three Flashes | No content flashes more than 3 times |\n| **2.3.3** Animation from Interactions | Motion animation can be disabled |\n| **2.4.8** Location | User location within site is available |\n| **2.4.9** Link Purpose (Link Only) | Link purpose clear from link text alone |\n| **2.4.10** Section Headings | Sections have headings |\n| **3.1.3** Unusual Words | Definitions available for unusual words |\n| **3.1.4** Abbreviations | Abbreviations expanded |\n| **3.1.5** Reading Level | Alternative content for complex text |\n| **3.1.6** Pronunciation | Pronunciation available where needed |\n| **3.2.5** Change on Request | Changes initiated only by user |\n| **3.3.5** Help | Context-sensitive help available |\n| **3.3.6** Error Prevention (All) | All form submissions can be reviewed |\n\n## Common ARIA patterns\n\n### Buttons\n```html\n<button>Label</button>\n<!-- or -->\n<button aria-label=\"Close dialog\">×</button>\n```\n\n### Links\n```html\n<a href=\"/page\">Descriptive link text</a>\n<!-- External links -->\n<a href=\"https://external.com\" target=\"_blank\" rel=\"noopener\">\n  External site\n  <span class=\"visually-hidden\">(opens in new tab)</span>\n</a>\n```\n\n### Form fields\n```html\n<label for=\"email\">Email address</label>\n<input type=\"email\" id=\"email\" aria-describedby=\"email-hint\">\n<p id=\"email-hint\">We'll never share your email.</p>\n```\n\n### Error states\n```html\n<label for=\"email\">Email</label>\n<input type=\"email\" id=\"email\" aria-invalid=\"true\" aria-describedby=\"email-error\">\n<p id=\"email-error\" role=\"alert\">Please enter a valid email address.</p>\n```\n\n### Navigation\n```html\n<nav aria-label=\"Main\">\n  <ul>\n    <li><a href=\"/\" aria-current=\"page\">Home</a></li>\n    <li><a href=\"/about\">About</a></li>\n  </ul>\n</nav>\n```\n\n### Modals\n```html\n<div role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"dialog-title\">\n  <h2 id=\"dialog-title\">Confirm Action</h2>\n  <!-- content -->\n</div>\n```\n\n### Live regions\n```html\n<!-- Polite (waits for pause in speech) -->\n<div aria-live=\"polite\">Status update here</div>\n\n<!-- Assertive (interrupts immediately) -->\n<div aria-live=\"assertive\" role=\"alert\">Error message here</div>\n\n<!-- Status (polite, implicit) -->\n<div role=\"status\">Loading complete</div>\n```\n\n## Testing tools\n\n| Tool | Type | URL |\n|------|------|-----|\n| axe DevTools | Browser extension | [deque.com/axe](https://www.deque.com/axe/) |\n| WAVE | Browser extension | [wave.webaim.org](https://wave.webaim.org/) |\n| Lighthouse | Built into Chrome | DevTools → Lighthouse |\n| NVDA | Screen reader (Windows) | [nvaccess.org](https://www.nvaccess.org/) |\n| VoiceOver | Screen reader (Mac) | Built into macOS |\n| Colour Contrast Analyser | Desktop app | [tpgi.com](https://www.tpgi.com/color-contrast-checker/) |\n","isInternal":false,"tokens":1980,"sizeBytes":7324},{"name":"SKILL.md","path":"src/resources/skills/accessibility/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/accessibility/SKILL.md","title":"accessibility","category":"anthropic-skill","format":"markdown","content":"---\nname: accessibility\ndescription: Audit and improve web accessibility following WCAG 2.1 guidelines. Use when asked to \"improve accessibility\", \"a11y audit\", \"WCAG compliance\", \"screen reader support\", \"keyboard navigation\", or \"make accessible\".\nlicense: MIT\nmetadata:\n  author: web-quality-skills\n  version: \"1.0\"\n---\n\n# Accessibility (a11y)\n\nComprehensive accessibility guidelines based on WCAG 2.1 and Lighthouse accessibility audits. Goal: make content usable by everyone, including people with disabilities.\n\n## WCAG Principles: POUR\n\n| Principle | Description |\n|-----------|-------------|\n| **P**erceivable | Content can be perceived through different senses |\n| **O**perable | Interface can be operated by all users |\n| **U**nderstandable | Content and interface are understandable |\n| **R**obust | Content works with assistive technologies |\n\n## Conformance levels\n\n| Level | Requirement | Target |\n|-------|-------------|--------|\n| **A** | Minimum accessibility | Must pass |\n| **AA** | Standard compliance | Should pass (legal requirement in many jurisdictions) |\n| **AAA** | Enhanced accessibility | Nice to have |\n\n---\n\n## Perceivable\n\n### Text alternatives (1.1)\n\n**Images require alt text:**\n```html\n<!-- ❌ Missing alt -->\n<img src=\"chart.png\">\n\n<!-- ✅ Descriptive alt -->\n<img src=\"chart.png\" alt=\"Bar chart showing 40% increase in Q3 sales\">\n\n<!-- ✅ Decorative image (empty alt) -->\n<img src=\"decorative-border.png\" alt=\"\" role=\"presentation\">\n\n<!-- ✅ Complex image with longer description -->\n<figure>\n  <img src=\"infographic.png\" alt=\"2024 market trends infographic\" \n       aria-describedby=\"infographic-desc\">\n  <figcaption id=\"infographic-desc\">\n    <!-- Detailed description -->\n  </figcaption>\n</figure>\n```\n\n**Icon buttons need accessible names:**\n```html\n<!-- ❌ No accessible name -->\n<button><svg><!-- menu icon --></svg></button>\n\n<!-- ✅ Using aria-label -->\n<button aria-label=\"Open menu\">\n  <svg aria-hidden=\"true\"><!-- menu icon --></svg>\n</button>\n\n<!-- ✅ Using visually hidden text -->\n<button>\n  <svg aria-hidden=\"true\"><!-- menu icon --></svg>\n  <span class=\"visually-hidden\">Open menu</span>\n</button>\n```\n\n**Visually hidden class:**\n```css\n.visually-hidden {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: -1px;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  white-space: nowrap;\n  border: 0;\n}\n```\n\n### Color contrast (1.4.3, 1.4.6)\n\n| Text Size | AA minimum | AAA enhanced |\n|-----------|------------|--------------|\n| Normal text (< 18px / < 14px bold) | 4.5:1 | 7:1 |\n| Large text (≥ 18px / ≥ 14px bold) | 3:1 | 4.5:1 |\n| UI components & graphics | 3:1 | 3:1 |\n\n```css\n/* ❌ Low contrast (2.5:1) */\n.low-contrast {\n  color: #999;\n  background: #fff;\n}\n\n/* ✅ Sufficient contrast (7:1) */\n.high-contrast {\n  color: #333;\n  background: #fff;\n}\n\n/* ✅ Focus states need contrast too */\n:focus-visible {\n  outline: 2px solid #005fcc;\n  outline-offset: 2px;\n}\n```\n\n**Don't rely on color alone:**\n```html\n<!-- ❌ Only color indicates error -->\n<input class=\"error-border\">\n<style>.error-border { border-color: red; }</style>\n\n<!-- ✅ Color + icon + text -->\n<div class=\"field-error\">\n  <input aria-invalid=\"true\" aria-describedby=\"email-error\">\n  <span id=\"email-error\" class=\"error-message\">\n    <svg aria-hidden=\"true\"><!-- error icon --></svg>\n    Please enter a valid email address\n  </span>\n</div>\n```\n\n### Media alternatives (1.2)\n\n```html\n<!-- Video with captions -->\n<video controls>\n  <source src=\"video.mp4\" type=\"video/mp4\">\n  <track kind=\"captions\" src=\"captions.vtt\" srclang=\"en\" label=\"English\" default>\n  <track kind=\"descriptions\" src=\"descriptions.vtt\" srclang=\"en\" label=\"Descriptions\">\n</video>\n\n<!-- Audio with transcript -->\n<audio controls>\n  <source src=\"podcast.mp3\" type=\"audio/mp3\">\n</audio>\n<details>\n  <summary>Transcript</summary>\n  <p>Full transcript text...</p>\n</details>\n```\n\n---\n\n## Operable\n\n### Keyboard accessible (2.1)\n\n**All functionality must be keyboard accessible:**\n```javascript\n// ❌ Only handles click\nelement.addEventListener('click', handleAction);\n\n// ✅ Handles both click and keyboard\nelement.addEventListener('click', handleAction);\nelement.addEventListener('keydown', (e) => {\n  if (e.key === 'Enter' || e.key === ' ') {\n    e.preventDefault();\n    handleAction();\n  }\n});\n```\n\n**No keyboard traps:**\n```javascript\n// Modal focus management\nfunction openModal(modal) {\n  const focusableElements = modal.querySelectorAll(\n    'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n  );\n  const firstElement = focusableElements[0];\n  const lastElement = focusableElements[focusableElements.length - 1];\n  \n  // Trap focus within modal\n  modal.addEventListener('keydown', (e) => {\n    if (e.key === 'Tab') {\n      if (e.shiftKey && document.activeElement === firstElement) {\n        e.preventDefault();\n        lastElement.focus();\n      } else if (!e.shiftKey && document.activeElement === lastElement) {\n        e.preventDefault();\n        firstElement.focus();\n      }\n    }\n    if (e.key === 'Escape') {\n      closeModal();\n    }\n  });\n  \n  firstElement.focus();\n}\n```\n\n### Focus visible (2.4.7)\n\n```css\n/* ❌ Never remove focus outlines */\n*:focus { outline: none; }\n\n/* ✅ Use :focus-visible for keyboard-only focus */\n:focus {\n  outline: none;\n}\n\n:focus-visible {\n  outline: 2px solid #005fcc;\n  outline-offset: 2px;\n}\n\n/* ✅ Or custom focus styles */\nbutton:focus-visible {\n  box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.5);\n}\n```\n\n### Skip links (2.4.1)\n\n```html\n<body>\n  <a href=\"#main-content\" class=\"skip-link\">Skip to main content</a>\n  <header><!-- navigation --></header>\n  <main id=\"main-content\" tabindex=\"-1\">\n    <!-- main content -->\n  </main>\n</body>\n```\n\n```css\n.skip-link {\n  position: absolute;\n  top: -40px;\n  left: 0;\n  background: #000;\n  color: #fff;\n  padding: 8px 16px;\n  z-index: 100;\n}\n\n.skip-link:focus {\n  top: 0;\n}\n```\n\n### Timing (2.2)\n\n```javascript\n// Allow users to extend time limits\nfunction showSessionWarning() {\n  const modal = createModal({\n    title: 'Session Expiring',\n    content: 'Your session will expire in 2 minutes.',\n    actions: [\n      { label: 'Extend session', action: extendSession },\n      { label: 'Log out', action: logout }\n    ],\n    timeout: 120000 // 2 minutes to respond\n  });\n}\n```\n\n### Motion (2.3)\n\n```css\n/* Respect reduced motion preference */\n@media (prefers-reduced-motion: reduce) {\n  *,\n  *::before,\n  *::after {\n    animation-duration: 0.01ms !important;\n    animation-iteration-count: 1 !important;\n    transition-duration: 0.01ms !important;\n    scroll-behavior: auto !important;\n  }\n}\n```\n\n---\n\n## Understandable\n\n### Page language (3.1.1)\n\n```html\n<!-- ❌ No language specified -->\n<html>\n\n<!-- ✅ Language specified -->\n<html lang=\"en\">\n\n<!-- ✅ Language changes within page -->\n<p>The French word for hello is <span lang=\"fr\">bonjour</span>.</p>\n```\n\n### Consistent navigation (3.2.3)\n\n```html\n<!-- Navigation should be consistent across pages -->\n<nav aria-label=\"Main\">\n  <ul>\n    <li><a href=\"/\" aria-current=\"page\">Home</a></li>\n    <li><a href=\"/products\">Products</a></li>\n    <li><a href=\"/about\">About</a></li>\n  </ul>\n</nav>\n```\n\n### Form labels (3.3.2)\n\n```html\n<!-- ❌ No label association -->\n<input type=\"email\" placeholder=\"Email\">\n\n<!-- ✅ Explicit label -->\n<label for=\"email\">Email address</label>\n<input type=\"email\" id=\"email\" name=\"email\" \n       autocomplete=\"email\" required>\n\n<!-- ✅ Implicit label -->\n<label>\n  Email address\n  <input type=\"email\" name=\"email\" autocomplete=\"email\" required>\n</label>\n\n<!-- ✅ With instructions -->\n<label for=\"password\">Password</label>\n<input type=\"password\" id=\"password\" \n       aria-describedby=\"password-requirements\">\n<p id=\"password-requirements\">\n  Must be at least 8 characters with one number.\n</p>\n```\n\n### Error handling (3.3.1, 3.3.3)\n\n```html\n<!-- Announce errors to screen readers -->\n<form novalidate>\n  <div class=\"field\" aria-live=\"polite\">\n    <label for=\"email\">Email</label>\n    <input type=\"email\" id=\"email\" \n           aria-invalid=\"true\"\n           aria-describedby=\"email-error\">\n    <p id=\"email-error\" class=\"error\" role=\"alert\">\n      Please enter a valid email address (e.g., name@example.com)\n    </p>\n  </div>\n</form>\n```\n\n```javascript\n// Focus first error on submit\nform.addEventListener('submit', (e) => {\n  const firstError = form.querySelector('[aria-invalid=\"true\"]');\n  if (firstError) {\n    e.preventDefault();\n    firstError.focus();\n    \n    // Announce error summary\n    const errorSummary = document.getElementById('error-summary');\n    errorSummary.textContent = `${errors.length} errors found. Please fix them and try again.`;\n    errorSummary.focus();\n  }\n});\n```\n\n---\n\n## Robust\n\n### Valid HTML (4.1.1)\n\n```html\n<!-- ❌ Duplicate IDs -->\n<div id=\"content\">...</div>\n<div id=\"content\">...</div>\n\n<!-- ❌ Invalid nesting -->\n<a href=\"/\"><button>Click</button></a>\n\n<!-- ✅ Unique IDs -->\n<div id=\"main-content\">...</div>\n<div id=\"sidebar-content\">...</div>\n\n<!-- ✅ Proper nesting -->\n<a href=\"/\" class=\"button-link\">Click</a>\n```\n\n### ARIA usage (4.1.2)\n\n**Prefer native elements:**\n```html\n<!-- ❌ ARIA role on div -->\n<div role=\"button\" tabindex=\"0\">Click me</div>\n\n<!-- ✅ Native button -->\n<button>Click me</button>\n\n<!-- ❌ ARIA checkbox -->\n<div role=\"checkbox\" aria-checked=\"false\">Option</div>\n\n<!-- ✅ Native checkbox -->\n<label><input type=\"checkbox\"> Option</label>\n```\n\n**When ARIA is needed:**\n```html\n<!-- Custom tabs component -->\n<div role=\"tablist\" aria-label=\"Product information\">\n  <button role=\"tab\" id=\"tab-1\" aria-selected=\"true\" \n          aria-controls=\"panel-1\">Description</button>\n  <button role=\"tab\" id=\"tab-2\" aria-selected=\"false\" \n          aria-controls=\"panel-2\" tabindex=\"-1\">Reviews</button>\n</div>\n<div role=\"tabpanel\" id=\"panel-1\" aria-labelledby=\"tab-1\">\n  <!-- Panel content -->\n</div>\n<div role=\"tabpanel\" id=\"panel-2\" aria-labelledby=\"tab-2\" hidden>\n  <!-- Panel content -->\n</div>\n```\n\n### Live regions (4.1.3)\n\n```html\n<!-- Status updates -->\n<div aria-live=\"polite\" aria-atomic=\"true\" class=\"status\">\n  <!-- Content updates announced to screen readers -->\n</div>\n\n<!-- Urgent alerts -->\n<div role=\"alert\" aria-live=\"assertive\">\n  <!-- Interrupts current announcement -->\n</div>\n```\n\n```javascript\n// Announce dynamic content changes\nfunction showNotification(message, type = 'polite') {\n  const container = document.getElementById(`${type}-announcer`);\n  container.textContent = ''; // Clear first\n  requestAnimationFrame(() => {\n    container.textContent = message;\n  });\n}\n```\n\n---\n\n## Testing checklist\n\n### Automated testing\n```bash\n# Lighthouse accessibility audit\nnpx lighthouse https://example.com --only-categories=accessibility\n\n# axe-core\nnpm install @axe-core/cli -g\naxe https://example.com\n```\n\n### Manual testing\n\n- [ ] **Keyboard navigation:** Tab through entire page, use Enter/Space to activate\n- [ ] **Screen reader:** Test with VoiceOver (Mac), NVDA (Windows), or TalkBack (Android)\n- [ ] **Zoom:** Content usable at 200% zoom\n- [ ] **High contrast:** Test with Windows High Contrast Mode\n- [ ] **Reduced motion:** Test with `prefers-reduced-motion: reduce`\n- [ ] **Focus order:** Logical and follows visual order\n\n### Screen reader commands\n\n| Action | VoiceOver (Mac) | NVDA (Windows) |\n|--------|-----------------|----------------|\n| Start/Stop | ⌘ + F5 | Ctrl + Alt + N |\n| Next item | VO + → | ↓ |\n| Previous item | VO + ← | ↑ |\n| Activate | VO + Space | Enter |\n| Headings list | VO + U, then arrows | H / Shift + H |\n| Links list | VO + U | K / Shift + K |\n\n---\n\n## Common issues by impact\n\n### Critical (fix immediately)\n1. Missing form labels\n2. Missing image alt text\n3. Insufficient color contrast\n4. Keyboard traps\n5. No focus indicators\n\n### Serious (fix before launch)\n1. Missing page language\n2. Missing heading structure\n3. Non-descriptive link text\n4. Auto-playing media\n5. Missing skip links\n\n### Moderate (fix soon)\n1. Missing ARIA labels on icons\n2. Inconsistent navigation\n3. Missing error identification\n4. Timing without controls\n5. Missing landmark regions\n\n## References\n\n- [WCAG 2.1 Quick Reference](https://www.w3.org/WAI/WCAG21/quickref/)\n- [WAI-ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/)\n- [Deque axe Rules](https://dequeuniversity.com/rules/axe/)\n- [Web Quality Audit](../web-quality-audit/SKILL.md)\n","frontmatter":{"name":"accessibility","description":"Audit and improve web accessibility following WCAG 2.1 guidelines. Use when asked to \"improve accessibility\", \"a11y audit\", \"WCAG compliance\", \"screen reader support\", \"keyboard navigation\", or \"make accessible\".","license":"MIT","metadata":{"author":"web-quality-skills","version":"1.0"}},"isInternal":false,"tokens":3275,"sizeBytes":12388},{"name":"authentication.md","path":"src/resources/skills/agent-browser/references/authentication.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/agent-browser/references/authentication.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Authentication Patterns\n\nLogin flows, session persistence, OAuth, 2FA, and authenticated browsing.\n\n**Related**: [session-management.md](session-management.md) for state persistence details, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Login Flow](#basic-login-flow)\n- [Saving Authentication State](#saving-authentication-state)\n- [Restoring Authentication](#restoring-authentication)\n- [OAuth / SSO Flows](#oauth--sso-flows)\n- [Two-Factor Authentication](#two-factor-authentication)\n- [HTTP Basic Auth](#http-basic-auth)\n- [Cookie-Based Auth](#cookie-based-auth)\n- [Token Refresh Handling](#token-refresh-handling)\n- [Security Best Practices](#security-best-practices)\n\n## Basic Login Flow\n\n```bash\n# Navigate to login page\nagent-browser open https://app.example.com/login\nagent-browser wait --load networkidle\n\n# Get form elements\nagent-browser snapshot -i\n# Output: @e1 [input type=\"email\"], @e2 [input type=\"password\"], @e3 [button] \"Sign In\"\n\n# Fill credentials\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\n\n# Submit\nagent-browser click @e3\nagent-browser wait --load networkidle\n\n# Verify login succeeded\nagent-browser get url  # Should be dashboard, not login\n```\n\n## Saving Authentication State\n\nAfter logging in, save state for reuse:\n\n```bash\n# Login first (see above)\nagent-browser open https://app.example.com/login\nagent-browser snapshot -i\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\nagent-browser click @e3\nagent-browser wait --url \"**/dashboard\"\n\n# Save authenticated state\nagent-browser state save ./auth-state.json\n```\n\n## Restoring Authentication\n\nSkip login by loading saved state:\n\n```bash\n# Load saved auth state\nagent-browser state load ./auth-state.json\n\n# Navigate directly to protected page\nagent-browser open https://app.example.com/dashboard\n\n# Verify authenticated\nagent-browser snapshot -i\n```\n\n## OAuth / SSO Flows\n\nFor OAuth redirects:\n\n```bash\n# Start OAuth flow\nagent-browser open https://app.example.com/auth/google\n\n# Handle redirects automatically\nagent-browser wait --url \"**/accounts.google.com**\"\nagent-browser snapshot -i\n\n# Fill Google credentials\nagent-browser fill @e1 \"user@gmail.com\"\nagent-browser click @e2  # Next button\nagent-browser wait 2000\nagent-browser snapshot -i\nagent-browser fill @e3 \"password\"\nagent-browser click @e4  # Sign in\n\n# Wait for redirect back\nagent-browser wait --url \"**/app.example.com**\"\nagent-browser state save ./oauth-state.json\n```\n\n## Two-Factor Authentication\n\nHandle 2FA with manual intervention:\n\n```bash\n# Login with credentials\nagent-browser open https://app.example.com/login --headed  # Show browser\nagent-browser snapshot -i\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\nagent-browser click @e3\n\n# Wait for user to complete 2FA manually\necho \"Complete 2FA in the browser window...\"\nagent-browser wait --url \"**/dashboard\" --timeout 120000\n\n# Save state after 2FA\nagent-browser state save ./2fa-state.json\n```\n\n## HTTP Basic Auth\n\nFor sites using HTTP Basic Authentication:\n\n```bash\n# Set credentials before navigation\nagent-browser set credentials username password\n\n# Navigate to protected resource\nagent-browser open https://protected.example.com/api\n```\n\n## Cookie-Based Auth\n\nManually set authentication cookies:\n\n```bash\n# Set auth cookie\nagent-browser cookies set session_token \"abc123xyz\"\n\n# Navigate to protected page\nagent-browser open https://app.example.com/dashboard\n```\n\n## Token Refresh Handling\n\nFor sessions with expiring tokens:\n\n```bash\n#!/bin/bash\n# Wrapper that handles token refresh\n\nSTATE_FILE=\"./auth-state.json\"\n\n# Try loading existing state\nif [[ -f \"$STATE_FILE\" ]]; then\n    agent-browser state load \"$STATE_FILE\"\n    agent-browser open https://app.example.com/dashboard\n\n    # Check if session is still valid\n    URL=$(agent-browser get url)\n    if [[ \"$URL\" == *\"/login\"* ]]; then\n        echo \"Session expired, re-authenticating...\"\n        # Perform fresh login\n        agent-browser snapshot -i\n        agent-browser fill @e1 \"$USERNAME\"\n        agent-browser fill @e2 \"$PASSWORD\"\n        agent-browser click @e3\n        agent-browser wait --url \"**/dashboard\"\n        agent-browser state save \"$STATE_FILE\"\n    fi\nelse\n    # First-time login\n    agent-browser open https://app.example.com/login\n    # ... login flow ...\nfi\n```\n\n## Security Best Practices\n\n1. **Never commit state files** - They contain session tokens\n   ```bash\n   echo \"*.auth-state.json\" >> .gitignore\n   ```\n\n2. **Use environment variables for credentials**\n   ```bash\n   agent-browser fill @e1 \"$APP_USERNAME\"\n   agent-browser fill @e2 \"$APP_PASSWORD\"\n   ```\n\n3. **Clean up after automation**\n   ```bash\n   agent-browser cookies clear\n   rm -f ./auth-state.json\n   ```\n\n4. **Use short-lived sessions for CI/CD**\n   ```bash\n   # Don't persist state in CI\n   agent-browser open https://app.example.com/login\n   # ... login and perform actions ...\n   agent-browser close  # Session ends, nothing persisted\n   ```\n","isInternal":false,"tokens":1188,"sizeBytes":5023},{"name":"commands.md","path":"src/resources/skills/agent-browser/references/commands.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/agent-browser/references/commands.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Command Reference\n\nComplete reference for all agent-browser commands. For quick start and common patterns, see SKILL.md.\n\n## Navigation\n\n```bash\nagent-browser open <url>      # Navigate to URL (aliases: goto, navigate)\n                              # Supports: https://, http://, file://, about:, data://\n                              # Auto-prepends https:// if no protocol given\nagent-browser back            # Go back\nagent-browser forward         # Go forward\nagent-browser reload          # Reload page\nagent-browser close           # Close browser (aliases: quit, exit)\nagent-browser connect 9222    # Connect to browser via CDP port\n```\n\n## Snapshot (page analysis)\n\n```bash\nagent-browser snapshot            # Full accessibility tree\nagent-browser snapshot -i         # Interactive elements only (recommended)\nagent-browser snapshot -c         # Compact output\nagent-browser snapshot -d 3       # Limit depth to 3\nagent-browser snapshot -s \"#main\" # Scope to CSS selector\n```\n\n## Interactions (use @refs from snapshot)\n\n```bash\nagent-browser click @e1           # Click\nagent-browser click @e1 --new-tab # Click and open in new tab\nagent-browser dblclick @e1        # Double-click\nagent-browser focus @e1           # Focus element\nagent-browser fill @e2 \"text\"     # Clear and type\nagent-browser type @e2 \"text\"     # Type without clearing\nagent-browser press Enter         # Press key (alias: key)\nagent-browser press Control+a     # Key combination\nagent-browser keydown Shift       # Hold key down\nagent-browser keyup Shift         # Release key\nagent-browser hover @e1           # Hover\nagent-browser check @e1           # Check checkbox\nagent-browser uncheck @e1         # Uncheck checkbox\nagent-browser select @e1 \"value\"  # Select dropdown option\nagent-browser select @e1 \"a\" \"b\"  # Select multiple options\nagent-browser scroll down 500     # Scroll page (default: down 300px)\nagent-browser scrollintoview @e1  # Scroll element into view (alias: scrollinto)\nagent-browser drag @e1 @e2        # Drag and drop\nagent-browser upload @e1 file.pdf # Upload files\n```\n\n## Get Information\n\n```bash\nagent-browser get text @e1        # Get element text\nagent-browser get html @e1        # Get innerHTML\nagent-browser get value @e1       # Get input value\nagent-browser get attr @e1 href   # Get attribute\nagent-browser get title           # Get page title\nagent-browser get url             # Get current URL\nagent-browser get count \".item\"   # Count matching elements\nagent-browser get box @e1         # Get bounding box\nagent-browser get styles @e1      # Get computed styles (font, color, bg, etc.)\n```\n\n## Check State\n\n```bash\nagent-browser is visible @e1      # Check if visible\nagent-browser is enabled @e1      # Check if enabled\nagent-browser is checked @e1      # Check if checked\n```\n\n## Screenshots and PDF\n\n```bash\nagent-browser screenshot          # Save to temporary directory\nagent-browser screenshot path.png # Save to specific path\nagent-browser screenshot --full   # Full page\nagent-browser pdf output.pdf      # Save as PDF\n```\n\n## Video Recording\n\n```bash\nagent-browser record start ./demo.webm    # Start recording\nagent-browser click @e1                   # Perform actions\nagent-browser record stop                 # Stop and save video\nagent-browser record restart ./take2.webm # Stop current + start new\n```\n\n## Wait\n\n```bash\nagent-browser wait @e1                     # Wait for element\nagent-browser wait 2000                    # Wait milliseconds\nagent-browser wait --text \"Success\"        # Wait for text (or -t)\nagent-browser wait --url \"**/dashboard\"    # Wait for URL pattern (or -u)\nagent-browser wait --load networkidle      # Wait for network idle (or -l)\nagent-browser wait --fn \"window.ready\"     # Wait for JS condition (or -f)\n```\n\n## Mouse Control\n\n```bash\nagent-browser mouse move 100 200      # Move mouse\nagent-browser mouse down left         # Press button\nagent-browser mouse up left           # Release button\nagent-browser mouse wheel 100         # Scroll wheel\n```\n\n## Semantic Locators (alternative to refs)\n\n```bash\nagent-browser find role button click --name \"Submit\"\nagent-browser find text \"Sign In\" click\nagent-browser find text \"Sign In\" click --exact      # Exact match only\nagent-browser find label \"Email\" fill \"user@test.com\"\nagent-browser find placeholder \"Search\" type \"query\"\nagent-browser find alt \"Logo\" click\nagent-browser find title \"Close\" click\nagent-browser find testid \"submit-btn\" click\nagent-browser find first \".item\" click\nagent-browser find last \".item\" click\nagent-browser find nth 2 \"a\" hover\n```\n\n## Browser Settings\n\n```bash\nagent-browser set viewport 1920 1080          # Set viewport size\nagent-browser set device \"iPhone 14\"          # Emulate device\nagent-browser set geo 37.7749 -122.4194       # Set geolocation (alias: geolocation)\nagent-browser set offline on                  # Toggle offline mode\nagent-browser set headers '{\"X-Key\":\"v\"}'     # Extra HTTP headers\nagent-browser set credentials user pass       # HTTP basic auth (alias: auth)\nagent-browser set media dark                  # Emulate color scheme\nagent-browser set media light reduced-motion  # Light mode + reduced motion\n```\n\n## Cookies and Storage\n\n```bash\nagent-browser cookies                     # Get all cookies\nagent-browser cookies set name value      # Set cookie\nagent-browser cookies clear               # Clear cookies\nagent-browser storage local               # Get all localStorage\nagent-browser storage local key           # Get specific key\nagent-browser storage local set k v       # Set value\nagent-browser storage local clear         # Clear all\n```\n\n## Network\n\n```bash\nagent-browser network route <url>              # Intercept requests\nagent-browser network route <url> --abort      # Block requests\nagent-browser network route <url> --body '{}'  # Mock response\nagent-browser network unroute [url]            # Remove routes\nagent-browser network requests                 # View tracked requests\nagent-browser network requests --filter api    # Filter requests\n```\n\n## Tabs and Windows\n\n```bash\nagent-browser tab                 # List tabs\nagent-browser tab new [url]       # New tab\nagent-browser tab 2               # Switch to tab by index\nagent-browser tab close           # Close current tab\nagent-browser tab close 2         # Close tab by index\nagent-browser window new          # New window\n```\n\n## Frames\n\n```bash\nagent-browser frame \"#iframe\"     # Switch to iframe\nagent-browser frame main          # Back to main frame\n```\n\n## Dialogs\n\n```bash\nagent-browser dialog accept [text]  # Accept dialog\nagent-browser dialog dismiss        # Dismiss dialog\n```\n\n## JavaScript\n\n```bash\nagent-browser eval \"document.title\"          # Simple expressions only\nagent-browser eval -b \"<base64>\"             # Any JavaScript (base64 encoded)\nagent-browser eval --stdin                   # Read script from stdin\n```\n\nUse `-b`/`--base64` or `--stdin` for reliable execution. Shell escaping with nested quotes and special characters is error-prone.\n\n```bash\n# Base64 encode your script, then:\nagent-browser eval -b \"ZG9jdW1lbnQucXVlcnlTZWxlY3RvcignW3NyYyo9Il9uZXh0Il0nKQ==\"\n\n# Or use stdin with heredoc for multiline scripts:\ncat <<'EOF' | agent-browser eval --stdin\nconst links = document.querySelectorAll('a');\nArray.from(links).map(a => a.href);\nEOF\n```\n\n## State Management\n\n```bash\nagent-browser state save auth.json    # Save cookies, storage, auth state\nagent-browser state load auth.json    # Restore saved state\n```\n\n## Global Options\n\n```bash\nagent-browser --session <name> ...    # Isolated browser session\nagent-browser --json ...              # JSON output for parsing\nagent-browser --headed ...            # Show browser window (not headless)\nagent-browser --full ...              # Full page screenshot (-f)\nagent-browser --cdp <port> ...        # Connect via Chrome DevTools Protocol\nagent-browser -p <provider> ...       # Cloud browser provider (--provider)\nagent-browser --proxy <url> ...       # Use proxy server\nagent-browser --proxy-bypass <hosts>  # Hosts to bypass proxy\nagent-browser --headers <json> ...    # HTTP headers scoped to URL's origin\nagent-browser --executable-path <p>   # Custom browser executable\nagent-browser --extension <path> ...  # Load browser extension (repeatable)\nagent-browser --ignore-https-errors   # Ignore SSL certificate errors\nagent-browser --help                  # Show help (-h)\nagent-browser --version               # Show version (-V)\nagent-browser <command> --help        # Show detailed help for a command\n```\n\n## Debugging\n\n```bash\nagent-browser --headed open example.com   # Show browser window\nagent-browser --cdp 9222 snapshot         # Connect via CDP port\nagent-browser connect 9222                # Alternative: connect command\nagent-browser console                     # View console messages\nagent-browser console --clear             # Clear console\nagent-browser errors                      # View page errors\nagent-browser errors --clear              # Clear errors\nagent-browser highlight @e1               # Highlight element\nagent-browser trace start                 # Start recording trace\nagent-browser trace stop trace.zip        # Stop and save trace\nagent-browser profiler start              # Start Chrome DevTools profiling\nagent-browser profiler stop trace.json    # Stop and save profile\n```\n\n## Environment Variables\n\n```bash\nAGENT_BROWSER_SESSION=\"mysession\"            # Default session name\nAGENT_BROWSER_EXECUTABLE_PATH=\"/path/chrome\" # Custom browser path\nAGENT_BROWSER_EXTENSIONS=\"/ext1,/ext2\"       # Comma-separated extension paths\nAGENT_BROWSER_PROVIDER=\"browserbase\"         # Cloud browser provider\nAGENT_BROWSER_STREAM_PORT=\"9223\"             # WebSocket streaming port\nAGENT_BROWSER_HOME=\"/path/to/agent-browser\"  # Custom install location\n```\n","isInternal":false,"tokens":2205,"sizeBytes":9825},{"name":"profiling.md","path":"src/resources/skills/agent-browser/references/profiling.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/agent-browser/references/profiling.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Profiling\n\nCapture Chrome DevTools performance profiles during browser automation for performance analysis.\n\n**Related**: [commands.md](commands.md) for full command reference, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Profiling](#basic-profiling)\n- [Profiler Commands](#profiler-commands)\n- [Categories](#categories)\n- [Use Cases](#use-cases)\n- [Output Format](#output-format)\n- [Viewing Profiles](#viewing-profiles)\n- [Limitations](#limitations)\n\n## Basic Profiling\n\n```bash\n# Start profiling\nagent-browser profiler start\n\n# Perform actions\nagent-browser navigate https://example.com\nagent-browser click \"#button\"\nagent-browser wait 1000\n\n# Stop and save\nagent-browser profiler stop ./trace.json\n```\n\n## Profiler Commands\n\n```bash\n# Start profiling with default categories\nagent-browser profiler start\n\n# Start with custom trace categories\nagent-browser profiler start --categories \"devtools.timeline,v8.execute,blink.user_timing\"\n\n# Stop profiling and save to file\nagent-browser profiler stop ./trace.json\n```\n\n## Categories\n\nThe `--categories` flag accepts a comma-separated list of Chrome trace categories. Default categories include:\n\n- `devtools.timeline` -- standard DevTools performance traces\n- `v8.execute` -- time spent running JavaScript\n- `blink` -- renderer events\n- `blink.user_timing` -- `performance.mark()` / `performance.measure()` calls\n- `latencyInfo` -- input-to-latency tracking\n- `renderer.scheduler` -- task scheduling and execution\n- `toplevel` -- broad-spectrum basic events\n\nSeveral `disabled-by-default-*` categories are also included for detailed timeline, call stack, and V8 CPU profiling data.\n\n## Use Cases\n\n### Diagnosing Slow Page Loads\n\n```bash\nagent-browser profiler start\nagent-browser navigate https://app.example.com\nagent-browser wait --load networkidle\nagent-browser profiler stop ./page-load-profile.json\n```\n\n### Profiling User Interactions\n\n```bash\nagent-browser navigate https://app.example.com\nagent-browser profiler start\nagent-browser click \"#submit\"\nagent-browser wait 2000\nagent-browser profiler stop ./interaction-profile.json\n```\n\n### CI Performance Regression Checks\n\n```bash\n#!/bin/bash\nagent-browser profiler start\nagent-browser navigate https://app.example.com\nagent-browser wait --load networkidle\nagent-browser profiler stop \"./profiles/build-${BUILD_ID}.json\"\n```\n\n## Output Format\n\nThe output is a JSON file in Chrome Trace Event format:\n\n```json\n{\n  \"traceEvents\": [\n    { \"cat\": \"devtools.timeline\", \"name\": \"RunTask\", \"ph\": \"X\", \"ts\": 12345, \"dur\": 100, ... },\n    ...\n  ],\n  \"metadata\": {\n    \"clock-domain\": \"LINUX_CLOCK_MONOTONIC\"\n  }\n}\n```\n\nThe `metadata.clock-domain` field is set based on the host platform (Linux or macOS). On Windows it is omitted.\n\n## Viewing Profiles\n\nLoad the output JSON file in any of these tools:\n\n- **Chrome DevTools**: Performance panel > Load profile (Ctrl+Shift+I > Performance)\n- **Perfetto UI**: https://ui.perfetto.dev/ -- drag and drop the JSON file\n- **Trace Viewer**: `chrome://tracing` in any Chromium browser\n\n## Limitations\n\n- Only works with Chromium-based browsers (Chrome, Edge). Not supported on Firefox or WebKit.\n- Trace data accumulates in memory while profiling is active (capped at 5 million events). Stop profiling promptly after the area of interest.\n- Data collection on stop has a 30-second timeout. If the browser is unresponsive, the stop command may fail.\n","isInternal":false,"tokens":788,"sizeBytes":3405},{"name":"proxy-support.md","path":"src/resources/skills/agent-browser/references/proxy-support.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/agent-browser/references/proxy-support.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Proxy Support\n\nProxy configuration for geo-testing, rate limiting avoidance, and corporate environments.\n\n**Related**: [commands.md](commands.md) for global options, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Proxy Configuration](#basic-proxy-configuration)\n- [Authenticated Proxy](#authenticated-proxy)\n- [SOCKS Proxy](#socks-proxy)\n- [Proxy Bypass](#proxy-bypass)\n- [Common Use Cases](#common-use-cases)\n- [Verifying Proxy Connection](#verifying-proxy-connection)\n- [Troubleshooting](#troubleshooting)\n- [Best Practices](#best-practices)\n\n## Basic Proxy Configuration\n\nUse the `--proxy` flag or set proxy via environment variable:\n\n```bash\n# Via CLI flag\nagent-browser --proxy \"http://proxy.example.com:8080\" open https://example.com\n\n# Via environment variable\nexport HTTP_PROXY=\"http://proxy.example.com:8080\"\nagent-browser open https://example.com\n\n# HTTPS proxy\nexport HTTPS_PROXY=\"https://proxy.example.com:8080\"\nagent-browser open https://example.com\n\n# Both\nexport HTTP_PROXY=\"http://proxy.example.com:8080\"\nexport HTTPS_PROXY=\"http://proxy.example.com:8080\"\nagent-browser open https://example.com\n```\n\n## Authenticated Proxy\n\nFor proxies requiring authentication:\n\n```bash\n# Include credentials in URL\nexport HTTP_PROXY=\"http://username:password@proxy.example.com:8080\"\nagent-browser open https://example.com\n```\n\n## SOCKS Proxy\n\n```bash\n# SOCKS5 proxy\nexport ALL_PROXY=\"socks5://proxy.example.com:1080\"\nagent-browser open https://example.com\n\n# SOCKS5 with auth\nexport ALL_PROXY=\"socks5://user:pass@proxy.example.com:1080\"\nagent-browser open https://example.com\n```\n\n## Proxy Bypass\n\nSkip proxy for specific domains using `--proxy-bypass` or `NO_PROXY`:\n\n```bash\n# Via CLI flag\nagent-browser --proxy \"http://proxy.example.com:8080\" --proxy-bypass \"localhost,*.internal.com\" open https://example.com\n\n# Via environment variable\nexport NO_PROXY=\"localhost,127.0.0.1,.internal.company.com\"\nagent-browser open https://internal.company.com  # Direct connection\nagent-browser open https://external.com          # Via proxy\n```\n\n## Common Use Cases\n\n### Geo-Location Testing\n\n```bash\n#!/bin/bash\n# Test site from different regions using geo-located proxies\n\nPROXIES=(\n    \"http://us-proxy.example.com:8080\"\n    \"http://eu-proxy.example.com:8080\"\n    \"http://asia-proxy.example.com:8080\"\n)\n\nfor proxy in \"${PROXIES[@]}\"; do\n    export HTTP_PROXY=\"$proxy\"\n    export HTTPS_PROXY=\"$proxy\"\n\n    region=$(echo \"$proxy\" | grep -oP '^\\w+-\\w+')\n    echo \"Testing from: $region\"\n\n    agent-browser --session \"$region\" open https://example.com\n    agent-browser --session \"$region\" screenshot \"./screenshots/$region.png\"\n    agent-browser --session \"$region\" close\ndone\n```\n\n### Rotating Proxies for Scraping\n\n```bash\n#!/bin/bash\n# Rotate through proxy list to avoid rate limiting\n\nPROXY_LIST=(\n    \"http://proxy1.example.com:8080\"\n    \"http://proxy2.example.com:8080\"\n    \"http://proxy3.example.com:8080\"\n)\n\nURLS=(\n    \"https://site.com/page1\"\n    \"https://site.com/page2\"\n    \"https://site.com/page3\"\n)\n\nfor i in \"${!URLS[@]}\"; do\n    proxy_index=$((i % ${#PROXY_LIST[@]}))\n    export HTTP_PROXY=\"${PROXY_LIST[$proxy_index]}\"\n    export HTTPS_PROXY=\"${PROXY_LIST[$proxy_index]}\"\n\n    agent-browser open \"${URLS[$i]}\"\n    agent-browser get text body > \"output-$i.txt\"\n    agent-browser close\n\n    sleep 1  # Polite delay\ndone\n```\n\n### Corporate Network Access\n\n```bash\n#!/bin/bash\n# Access internal sites via corporate proxy\n\nexport HTTP_PROXY=\"http://corpproxy.company.com:8080\"\nexport HTTPS_PROXY=\"http://corpproxy.company.com:8080\"\nexport NO_PROXY=\"localhost,127.0.0.1,.company.com\"\n\n# External sites go through proxy\nagent-browser open https://external-vendor.com\n\n# Internal sites bypass proxy\nagent-browser open https://intranet.company.com\n```\n\n## Verifying Proxy Connection\n\n```bash\n# Check your apparent IP\nagent-browser open https://httpbin.org/ip\nagent-browser get text body\n# Should show proxy's IP, not your real IP\n```\n\n## Troubleshooting\n\n### Proxy Connection Failed\n\n```bash\n# Test proxy connectivity first\ncurl -x http://proxy.example.com:8080 https://httpbin.org/ip\n\n# Check if proxy requires auth\nexport HTTP_PROXY=\"http://user:pass@proxy.example.com:8080\"\n```\n\n### SSL/TLS Errors Through Proxy\n\nSome proxies perform SSL inspection. If you encounter certificate errors:\n\n```bash\n# For testing only - not recommended for production\nagent-browser open https://example.com --ignore-https-errors\n```\n\n### Slow Performance\n\n```bash\n# Use proxy only when necessary\nexport NO_PROXY=\"*.cdn.com,*.static.com\"  # Direct CDN access\n```\n\n## Best Practices\n\n1. **Use environment variables** - Don't hardcode proxy credentials\n2. **Set NO_PROXY appropriately** - Avoid routing local traffic through proxy\n3. **Test proxy before automation** - Verify connectivity with simple requests\n4. **Handle proxy failures gracefully** - Implement retry logic for unstable proxies\n5. **Rotate proxies for large scraping jobs** - Distribute load and avoid bans\n","isInternal":false,"tokens":1248,"sizeBytes":4971},{"name":"session-management.md","path":"src/resources/skills/agent-browser/references/session-management.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/agent-browser/references/session-management.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Session Management\n\nMultiple isolated browser sessions with state persistence and concurrent browsing.\n\n**Related**: [authentication.md](authentication.md) for login patterns, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Named Sessions](#named-sessions)\n- [Session Isolation Properties](#session-isolation-properties)\n- [Session State Persistence](#session-state-persistence)\n- [Common Patterns](#common-patterns)\n- [Default Session](#default-session)\n- [Session Cleanup](#session-cleanup)\n- [Best Practices](#best-practices)\n\n## Named Sessions\n\nUse `--session` flag to isolate browser contexts:\n\n```bash\n# Session 1: Authentication flow\nagent-browser --session auth open https://app.example.com/login\n\n# Session 2: Public browsing (separate cookies, storage)\nagent-browser --session public open https://example.com\n\n# Commands are isolated by session\nagent-browser --session auth fill @e1 \"user@example.com\"\nagent-browser --session public get text body\n```\n\n## Session Isolation Properties\n\nEach session has independent:\n- Cookies\n- LocalStorage / SessionStorage\n- IndexedDB\n- Cache\n- Browsing history\n- Open tabs\n\n## Session State Persistence\n\n### Save Session State\n\n```bash\n# Save cookies, storage, and auth state\nagent-browser state save /path/to/auth-state.json\n```\n\n### Load Session State\n\n```bash\n# Restore saved state\nagent-browser state load /path/to/auth-state.json\n\n# Continue with authenticated session\nagent-browser open https://app.example.com/dashboard\n```\n\n### State File Contents\n\n```json\n{\n  \"cookies\": [...],\n  \"localStorage\": {...},\n  \"sessionStorage\": {...},\n  \"origins\": [...]\n}\n```\n\n## Common Patterns\n\n### Authenticated Session Reuse\n\n```bash\n#!/bin/bash\n# Save login state once, reuse many times\n\nSTATE_FILE=\"/tmp/auth-state.json\"\n\n# Check if we have saved state\nif [[ -f \"$STATE_FILE\" ]]; then\n    agent-browser state load \"$STATE_FILE\"\n    agent-browser open https://app.example.com/dashboard\nelse\n    # Perform login\n    agent-browser open https://app.example.com/login\n    agent-browser snapshot -i\n    agent-browser fill @e1 \"$USERNAME\"\n    agent-browser fill @e2 \"$PASSWORD\"\n    agent-browser click @e3\n    agent-browser wait --load networkidle\n\n    # Save for future use\n    agent-browser state save \"$STATE_FILE\"\nfi\n```\n\n### Concurrent Scraping\n\n```bash\n#!/bin/bash\n# Scrape multiple sites concurrently\n\n# Start all sessions\nagent-browser --session site1 open https://site1.com &\nagent-browser --session site2 open https://site2.com &\nagent-browser --session site3 open https://site3.com &\nwait\n\n# Extract from each\nagent-browser --session site1 get text body > site1.txt\nagent-browser --session site2 get text body > site2.txt\nagent-browser --session site3 get text body > site3.txt\n\n# Cleanup\nagent-browser --session site1 close\nagent-browser --session site2 close\nagent-browser --session site3 close\n```\n\n### A/B Testing Sessions\n\n```bash\n# Test different user experiences\nagent-browser --session variant-a open \"https://app.com?variant=a\"\nagent-browser --session variant-b open \"https://app.com?variant=b\"\n\n# Compare\nagent-browser --session variant-a screenshot /tmp/variant-a.png\nagent-browser --session variant-b screenshot /tmp/variant-b.png\n```\n\n## Default Session\n\nWhen `--session` is omitted, commands use the default session:\n\n```bash\n# These use the same default session\nagent-browser open https://example.com\nagent-browser snapshot -i\nagent-browser close  # Closes default session\n```\n\n## Session Cleanup\n\n```bash\n# Close specific session\nagent-browser --session auth close\n\n# List active sessions\nagent-browser session list\n```\n\n## Best Practices\n\n### 1. Name Sessions Semantically\n\n```bash\n# GOOD: Clear purpose\nagent-browser --session github-auth open https://github.com\nagent-browser --session docs-scrape open https://docs.example.com\n\n# AVOID: Generic names\nagent-browser --session s1 open https://github.com\n```\n\n### 2. Always Clean Up\n\n```bash\n# Close sessions when done\nagent-browser --session auth close\nagent-browser --session scrape close\n```\n\n### 3. Handle State Files Securely\n\n```bash\n# Don't commit state files (contain auth tokens!)\necho \"*.auth-state.json\" >> .gitignore\n\n# Delete after use\nrm /tmp/auth-state.json\n```\n\n### 4. Timeout Long Sessions\n\n```bash\n# Set timeout for automated scripts\ntimeout 60 agent-browser --session long-task get text body\n```\n","isInternal":false,"tokens":1017,"sizeBytes":4337},{"name":"snapshot-refs.md","path":"src/resources/skills/agent-browser/references/snapshot-refs.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/agent-browser/references/snapshot-refs.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Snapshot and Refs\n\nCompact element references that reduce context usage dramatically for AI agents.\n\n**Related**: [commands.md](commands.md) for full command reference, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [How Refs Work](#how-refs-work)\n- [Snapshot Command](#the-snapshot-command)\n- [Using Refs](#using-refs)\n- [Ref Lifecycle](#ref-lifecycle)\n- [Best Practices](#best-practices)\n- [Ref Notation Details](#ref-notation-details)\n- [Troubleshooting](#troubleshooting)\n\n## How Refs Work\n\nTraditional approach:\n```\nFull DOM/HTML → AI parses → CSS selector → Action (~3000-5000 tokens)\n```\n\nagent-browser approach:\n```\nCompact snapshot → @refs assigned → Direct interaction (~200-400 tokens)\n```\n\n## The Snapshot Command\n\n```bash\n# Basic snapshot (shows page structure)\nagent-browser snapshot\n\n# Interactive snapshot (-i flag) - RECOMMENDED\nagent-browser snapshot -i\n```\n\n### Snapshot Output Format\n\n```\nPage: Example Site - Home\nURL: https://example.com\n\n@e1 [header]\n  @e2 [nav]\n    @e3 [a] \"Home\"\n    @e4 [a] \"Products\"\n    @e5 [a] \"About\"\n  @e6 [button] \"Sign In\"\n\n@e7 [main]\n  @e8 [h1] \"Welcome\"\n  @e9 [form]\n    @e10 [input type=\"email\"] placeholder=\"Email\"\n    @e11 [input type=\"password\"] placeholder=\"Password\"\n    @e12 [button type=\"submit\"] \"Log In\"\n\n@e13 [footer]\n  @e14 [a] \"Privacy Policy\"\n```\n\n## Using Refs\n\nOnce you have refs, interact directly:\n\n```bash\n# Click the \"Sign In\" button\nagent-browser click @e6\n\n# Fill email input\nagent-browser fill @e10 \"user@example.com\"\n\n# Fill password\nagent-browser fill @e11 \"password123\"\n\n# Submit the form\nagent-browser click @e12\n```\n\n## Ref Lifecycle\n\n**IMPORTANT**: Refs are invalidated when the page changes!\n\n```bash\n# Get initial snapshot\nagent-browser snapshot -i\n# @e1 [button] \"Next\"\n\n# Click triggers page change\nagent-browser click @e1\n\n# MUST re-snapshot to get new refs!\nagent-browser snapshot -i\n# @e1 [h1] \"Page 2\"  ← Different element now!\n```\n\n## Best Practices\n\n### 1. Always Snapshot Before Interacting\n\n```bash\n# CORRECT\nagent-browser open https://example.com\nagent-browser snapshot -i          # Get refs first\nagent-browser click @e1            # Use ref\n\n# WRONG\nagent-browser open https://example.com\nagent-browser click @e1            # Ref doesn't exist yet!\n```\n\n### 2. Re-Snapshot After Navigation\n\n```bash\nagent-browser click @e5            # Navigates to new page\nagent-browser snapshot -i          # Get new refs\nagent-browser click @e1            # Use new refs\n```\n\n### 3. Re-Snapshot After Dynamic Changes\n\n```bash\nagent-browser click @e1            # Opens dropdown\nagent-browser snapshot -i          # See dropdown items\nagent-browser click @e7            # Select item\n```\n\n### 4. Snapshot Specific Regions\n\nFor complex pages, snapshot specific areas:\n\n```bash\n# Snapshot just the form\nagent-browser snapshot @e9\n```\n\n## Ref Notation Details\n\n```\n@e1 [tag type=\"value\"] \"text content\" placeholder=\"hint\"\n│    │   │             │               │\n│    │   │             │               └─ Additional attributes\n│    │   │             └─ Visible text\n│    │   └─ Key attributes shown\n│    └─ HTML tag name\n└─ Unique ref ID\n```\n\n### Common Patterns\n\n```\n@e1 [button] \"Submit\"                    # Button with text\n@e2 [input type=\"email\"]                 # Email input\n@e3 [input type=\"password\"]              # Password input\n@e4 [a href=\"/page\"] \"Link Text\"         # Anchor link\n@e5 [select]                             # Dropdown\n@e6 [textarea] placeholder=\"Message\"     # Text area\n@e7 [div class=\"modal\"]                  # Container (when relevant)\n@e8 [img alt=\"Logo\"]                     # Image\n@e9 [checkbox] checked                   # Checked checkbox\n@e10 [radio] selected                    # Selected radio\n```\n\n## Troubleshooting\n\n### \"Ref not found\" Error\n\n```bash\n# Ref may have changed - re-snapshot\nagent-browser snapshot -i\n```\n\n### Element Not Visible in Snapshot\n\n```bash\n# Scroll down to reveal element\nagent-browser scroll down 1000\nagent-browser snapshot -i\n\n# Or wait for dynamic content\nagent-browser wait 1000\nagent-browser snapshot -i\n```\n\n### Too Many Elements\n\n```bash\n# Snapshot specific container\nagent-browser snapshot @e5\n\n# Or use get text for content-only extraction\nagent-browser get text @e5\n```\n","isInternal":false,"tokens":1129,"sizeBytes":4305},{"name":"video-recording.md","path":"src/resources/skills/agent-browser/references/video-recording.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/agent-browser/references/video-recording.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Video Recording\n\nCapture browser automation as video for debugging, documentation, or verification.\n\n**Related**: [commands.md](commands.md) for full command reference, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Recording](#basic-recording)\n- [Recording Commands](#recording-commands)\n- [Use Cases](#use-cases)\n- [Best Practices](#best-practices)\n- [Output Format](#output-format)\n- [Limitations](#limitations)\n\n## Basic Recording\n\n```bash\n# Start recording\nagent-browser record start ./demo.webm\n\n# Perform actions\nagent-browser open https://example.com\nagent-browser snapshot -i\nagent-browser click @e1\nagent-browser fill @e2 \"test input\"\n\n# Stop and save\nagent-browser record stop\n```\n\n## Recording Commands\n\n```bash\n# Start recording to file\nagent-browser record start ./output.webm\n\n# Stop current recording\nagent-browser record stop\n\n# Restart with new file (stops current + starts new)\nagent-browser record restart ./take2.webm\n```\n\n## Use Cases\n\n### Debugging Failed Automation\n\n```bash\n#!/bin/bash\n# Record automation for debugging\n\nagent-browser record start ./debug-$(date +%Y%m%d-%H%M%S).webm\n\n# Run your automation\nagent-browser open https://app.example.com\nagent-browser snapshot -i\nagent-browser click @e1 || {\n    echo \"Click failed - check recording\"\n    agent-browser record stop\n    exit 1\n}\n\nagent-browser record stop\n```\n\n### Documentation Generation\n\n```bash\n#!/bin/bash\n# Record workflow for documentation\n\nagent-browser record start ./docs/how-to-login.webm\n\nagent-browser open https://app.example.com/login\nagent-browser wait 1000  # Pause for visibility\n\nagent-browser snapshot -i\nagent-browser fill @e1 \"demo@example.com\"\nagent-browser wait 500\n\nagent-browser fill @e2 \"password\"\nagent-browser wait 500\n\nagent-browser click @e3\nagent-browser wait --load networkidle\nagent-browser wait 1000  # Show result\n\nagent-browser record stop\n```\n\n### CI/CD Test Evidence\n\n```bash\n#!/bin/bash\n# Record E2E test runs for CI artifacts\n\nTEST_NAME=\"${1:-e2e-test}\"\nRECORDING_DIR=\"./test-recordings\"\nmkdir -p \"$RECORDING_DIR\"\n\nagent-browser record start \"$RECORDING_DIR/$TEST_NAME-$(date +%s).webm\"\n\n# Run test\nif run_e2e_test; then\n    echo \"Test passed\"\nelse\n    echo \"Test failed - recording saved\"\nfi\n\nagent-browser record stop\n```\n\n## Best Practices\n\n### 1. Add Pauses for Clarity\n\n```bash\n# Slow down for human viewing\nagent-browser click @e1\nagent-browser wait 500  # Let viewer see result\n```\n\n### 2. Use Descriptive Filenames\n\n```bash\n# Include context in filename\nagent-browser record start ./recordings/login-flow-2024-01-15.webm\nagent-browser record start ./recordings/checkout-test-run-42.webm\n```\n\n### 3. Handle Recording in Error Cases\n\n```bash\n#!/bin/bash\nset -e\n\ncleanup() {\n    agent-browser record stop 2>/dev/null || true\n    agent-browser close 2>/dev/null || true\n}\ntrap cleanup EXIT\n\nagent-browser record start ./automation.webm\n# ... automation steps ...\n```\n\n### 4. Combine with Screenshots\n\n```bash\n# Record video AND capture key frames\nagent-browser record start ./flow.webm\n\nagent-browser open https://example.com\nagent-browser screenshot ./screenshots/step1-homepage.png\n\nagent-browser click @e1\nagent-browser screenshot ./screenshots/step2-after-click.png\n\nagent-browser record stop\n```\n\n## Output Format\n\n- Default format: WebM (VP8/VP9 codec)\n- Compatible with all modern browsers and video players\n- Compressed but high quality\n\n## Limitations\n\n- Recording adds slight overhead to automation\n- Large recordings can consume significant disk space\n- Some headless environments may have codec limitations\n","isInternal":false,"tokens":880,"sizeBytes":3569},{"name":"SKILL.md","path":"src/resources/skills/agent-browser/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/agent-browser/SKILL.md","title":"agent-browser","category":"anthropic-skill","format":"markdown","content":"---\nname: agent-browser\ndescription: Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to \"open a website\", \"fill out a form\", \"click a button\", \"take a screenshot\", \"scrape data from a page\", \"test this web app\", \"login to a site\", \"automate browser actions\", or any task requiring programmatic web interaction.\nallowed-tools: Bash(npx agent-browser:*), Bash(agent-browser:*)\n---\n\n# Browser Automation with agent-browser\n\n## Core Workflow\n\nEvery browser automation follows this pattern:\n\n1. **Navigate**: `agent-browser open <url>`\n2. **Snapshot**: `agent-browser snapshot -i` (get element refs like `@e1`, `@e2`)\n3. **Interact**: Use refs to click, fill, select\n4. **Re-snapshot**: After navigation or DOM changes, get fresh refs\n\n```bash\nagent-browser open https://example.com/form\nagent-browser snapshot -i\n# Output: @e1 [input type=\"email\"], @e2 [input type=\"password\"], @e3 [button] \"Submit\"\n\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\nagent-browser click @e3\nagent-browser wait --load networkidle\nagent-browser snapshot -i  # Check result\n```\n\n## Command Chaining\n\nCommands can be chained with `&&` in a single shell invocation. The browser persists between commands via a background daemon, so chaining is safe and more efficient than separate calls.\n\n```bash\n# Chain open + wait + snapshot in one call\nagent-browser open https://example.com && agent-browser wait --load networkidle && agent-browser snapshot -i\n\n# Chain multiple interactions\nagent-browser fill @e1 \"user@example.com\" && agent-browser fill @e2 \"password123\" && agent-browser click @e3\n\n# Navigate and capture\nagent-browser open https://example.com && agent-browser wait --load networkidle && agent-browser screenshot page.png\n```\n\n**When to chain:** Use `&&` when you don't need to read the output of an intermediate command before proceeding (e.g., open + wait + screenshot). Run commands separately when you need to parse the output first (e.g., snapshot to discover refs, then interact using those refs).\n\n## Essential Commands\n\n```bash\n# Navigation\nagent-browser open <url>              # Navigate (aliases: goto, navigate)\nagent-browser close                   # Close browser\n\n# Snapshot\nagent-browser snapshot -i             # Interactive elements with refs (recommended)\nagent-browser snapshot -i -C          # Include cursor-interactive elements (divs with onclick, cursor:pointer)\nagent-browser snapshot -s \"#selector\" # Scope to CSS selector\n\n# Interaction (use @refs from snapshot)\nagent-browser click @e1               # Click element\nagent-browser click @e1 --new-tab     # Click and open in new tab\nagent-browser fill @e2 \"text\"         # Clear and type text\nagent-browser type @e2 \"text\"         # Type without clearing\nagent-browser select @e1 \"option\"     # Select dropdown option\nagent-browser check @e1               # Check checkbox\nagent-browser press Enter             # Press key\nagent-browser keyboard type \"text\"    # Type at current focus (no selector)\nagent-browser keyboard inserttext \"text\"  # Insert without key events\nagent-browser scroll down 500         # Scroll page\nagent-browser scroll down 500 --selector \"div.content\"  # Scroll within a specific container\n\n# Get information\nagent-browser get text @e1            # Get element text\nagent-browser get url                 # Get current URL\nagent-browser get title               # Get page title\n\n# Wait\nagent-browser wait @e1                # Wait for element\nagent-browser wait --load networkidle # Wait for network idle\nagent-browser wait --url \"**/page\"    # Wait for URL pattern\nagent-browser wait 2000               # Wait milliseconds\n\n# Downloads\nagent-browser download @e1 ./file.pdf          # Click element to trigger download\nagent-browser wait --download ./output.zip     # Wait for any download to complete\nagent-browser --download-path ./downloads open <url>  # Set default download directory\n\n# Capture\nagent-browser screenshot              # Screenshot to temp dir\nagent-browser screenshot --full       # Full page screenshot\nagent-browser screenshot --annotate   # Annotated screenshot with numbered element labels\nagent-browser pdf output.pdf          # Save as PDF\n\n# Diff (compare page states)\nagent-browser diff snapshot                          # Compare current vs last snapshot\nagent-browser diff snapshot --baseline before.txt    # Compare current vs saved file\nagent-browser diff screenshot --baseline before.png  # Visual pixel diff\nagent-browser diff url <url1> <url2>                 # Compare two pages\nagent-browser diff url <url1> <url2> --wait-until networkidle  # Custom wait strategy\nagent-browser diff url <url1> <url2> --selector \"#main\"  # Scope to element\n```\n\n## Common Patterns\n\n### Form Submission\n\n```bash\nagent-browser open https://example.com/signup\nagent-browser snapshot -i\nagent-browser fill @e1 \"Jane Doe\"\nagent-browser fill @e2 \"jane@example.com\"\nagent-browser select @e3 \"California\"\nagent-browser check @e4\nagent-browser click @e5\nagent-browser wait --load networkidle\n```\n\n### Authentication with Auth Vault (Recommended)\n\n```bash\n# Save credentials once (encrypted with AGENT_BROWSER_ENCRYPTION_KEY)\n# Recommended: pipe password via stdin to avoid shell history exposure\necho \"pass\" | agent-browser auth save github --url https://github.com/login --username user --password-stdin\n\n# Login using saved profile (LLM never sees password)\nagent-browser auth login github\n\n# List/show/delete profiles\nagent-browser auth list\nagent-browser auth show github\nagent-browser auth delete github\n```\n\n### Authentication with State Persistence\n\n```bash\n# Login once and save state\nagent-browser open https://app.example.com/login\nagent-browser snapshot -i\nagent-browser fill @e1 \"$USERNAME\"\nagent-browser fill @e2 \"$PASSWORD\"\nagent-browser click @e3\nagent-browser wait --url \"**/dashboard\"\nagent-browser state save auth.json\n\n# Reuse in future sessions\nagent-browser state load auth.json\nagent-browser open https://app.example.com/dashboard\n```\n\n### Session Persistence\n\n```bash\n# Auto-save/restore cookies and localStorage across browser restarts\nagent-browser --session-name myapp open https://app.example.com/login\n# ... login flow ...\nagent-browser close  # State auto-saved to ~/.agent-browser/sessions/\n\n# Next time, state is auto-loaded\nagent-browser --session-name myapp open https://app.example.com/dashboard\n\n# Encrypt state at rest\nexport AGENT_BROWSER_ENCRYPTION_KEY=$(openssl rand -hex 32)\nagent-browser --session-name secure open https://app.example.com\n\n# Manage saved states\nagent-browser state list\nagent-browser state show myapp-default.json\nagent-browser state clear myapp\nagent-browser state clean --older-than 7\n```\n\n### Data Extraction\n\n```bash\nagent-browser open https://example.com/products\nagent-browser snapshot -i\nagent-browser get text @e5           # Get specific element text\nagent-browser get text body > page.txt  # Get all page text\n\n# JSON output for parsing\nagent-browser snapshot -i --json\nagent-browser get text @e1 --json\n```\n\n### Parallel Sessions\n\n```bash\nagent-browser --session site1 open https://site-a.com\nagent-browser --session site2 open https://site-b.com\n\nagent-browser --session site1 snapshot -i\nagent-browser --session site2 snapshot -i\n\nagent-browser session list\n```\n\n### Connect to Existing Chrome\n\n```bash\n# Auto-discover running Chrome with remote debugging enabled\nagent-browser --auto-connect open https://example.com\nagent-browser --auto-connect snapshot\n\n# Or with explicit CDP port\nagent-browser --cdp 9222 snapshot\n```\n\n### Color Scheme (Dark Mode)\n\n```bash\n# Persistent dark mode via flag (applies to all pages and new tabs)\nagent-browser --color-scheme dark open https://example.com\n\n# Or via environment variable\nAGENT_BROWSER_COLOR_SCHEME=dark agent-browser open https://example.com\n\n# Or set during session (persists for subsequent commands)\nagent-browser set media dark\n```\n\n### Visual Browser (Debugging)\n\n```bash\nagent-browser --headed open https://example.com\nagent-browser highlight @e1          # Highlight element\nagent-browser record start demo.webm # Record session\nagent-browser profiler start         # Start Chrome DevTools profiling\nagent-browser profiler stop trace.json # Stop and save profile (path optional)\n```\n\nUse `AGENT_BROWSER_HEADED=1` to enable headed mode via environment variable. Browser extensions work in both headed and headless mode.\n\n### Local Files (PDFs, HTML)\n\n```bash\n# Open local files with file:// URLs\nagent-browser --allow-file-access open file:///path/to/document.pdf\nagent-browser --allow-file-access open file:///path/to/page.html\nagent-browser screenshot output.png\n```\n\n### iOS Simulator (Mobile Safari)\n\n```bash\n# List available iOS simulators\nagent-browser device list\n\n# Launch Safari on a specific device\nagent-browser -p ios --device \"iPhone 16 Pro\" open https://example.com\n\n# Same workflow as desktop - snapshot, interact, re-snapshot\nagent-browser -p ios snapshot -i\nagent-browser -p ios tap @e1          # Tap (alias for click)\nagent-browser -p ios fill @e2 \"text\"\nagent-browser -p ios swipe up         # Mobile-specific gesture\n\n# Take screenshot\nagent-browser -p ios screenshot mobile.png\n\n# Close session (shuts down simulator)\nagent-browser -p ios close\n```\n\n**Requirements:** macOS with Xcode, Appium (`npm install -g appium && appium driver install xcuitest`)\n\n**Real devices:** Works with physical iOS devices if pre-configured. Use `--device \"<UDID>\"` where UDID is from `xcrun xctrace list devices`.\n\n## Security\n\nAll security features are opt-in. By default, agent-browser imposes no restrictions on navigation, actions, or output.\n\n### Content Boundaries (Recommended for AI Agents)\n\nEnable `--content-boundaries` to wrap page-sourced output in markers that help LLMs distinguish tool output from untrusted page content:\n\n```bash\nexport AGENT_BROWSER_CONTENT_BOUNDARIES=1\nagent-browser snapshot\n# Output:\n# --- AGENT_BROWSER_PAGE_CONTENT nonce=<hex> origin=https://example.com ---\n# [accessibility tree]\n# --- END_AGENT_BROWSER_PAGE_CONTENT nonce=<hex> ---\n```\n\n### Domain Allowlist\n\nRestrict navigation to trusted domains. Wildcards like `*.example.com` also match the bare domain `example.com`. Sub-resource requests, WebSocket, and EventSource connections to non-allowed domains are also blocked. Include CDN domains your target pages depend on:\n\n```bash\nexport AGENT_BROWSER_ALLOWED_DOMAINS=\"example.com,*.example.com\"\nagent-browser open https://example.com        # OK\nagent-browser open https://malicious.com       # Blocked\n```\n\n### Action Policy\n\nUse a policy file to gate destructive actions:\n\n```bash\nexport AGENT_BROWSER_ACTION_POLICY=./policy.json\n```\n\nExample `policy.json`:\n```json\n{\"default\": \"deny\", \"allow\": [\"navigate\", \"snapshot\", \"click\", \"scroll\", \"wait\", \"get\"]}\n```\n\nAuth vault operations (`auth login`, etc.) bypass action policy but domain allowlist still applies.\n\n### Output Limits\n\nPrevent context flooding from large pages:\n\n```bash\nexport AGENT_BROWSER_MAX_OUTPUT=50000\n```\n\n## Diffing (Verifying Changes)\n\nUse `diff snapshot` after performing an action to verify it had the intended effect. This compares the current accessibility tree against the last snapshot taken in the session.\n\n```bash\n# Typical workflow: snapshot -> action -> diff\nagent-browser snapshot -i          # Take baseline snapshot\nagent-browser click @e2            # Perform action\nagent-browser diff snapshot        # See what changed (auto-compares to last snapshot)\n```\n\nFor visual regression testing or monitoring:\n\n```bash\n# Save a baseline screenshot, then compare later\nagent-browser screenshot baseline.png\n# ... time passes or changes are made ...\nagent-browser diff screenshot --baseline baseline.png\n\n# Compare staging vs production\nagent-browser diff url https://staging.example.com https://prod.example.com --screenshot\n```\n\n`diff snapshot` output uses `+` for additions and `-` for removals, similar to git diff. `diff screenshot` produces a diff image with changed pixels highlighted in red, plus a mismatch percentage.\n\n## Timeouts and Slow Pages\n\nThe default Playwright timeout is 25 seconds for local browsers. This can be overridden with the `AGENT_BROWSER_DEFAULT_TIMEOUT` environment variable (value in milliseconds). For slow websites or large pages, use explicit waits instead of relying on the default timeout:\n\n```bash\n# Wait for network activity to settle (best for slow pages)\nagent-browser wait --load networkidle\n\n# Wait for a specific element to appear\nagent-browser wait \"#content\"\nagent-browser wait @e1\n\n# Wait for a specific URL pattern (useful after redirects)\nagent-browser wait --url \"**/dashboard\"\n\n# Wait for a JavaScript condition\nagent-browser wait --fn \"document.readyState === 'complete'\"\n\n# Wait a fixed duration (milliseconds) as a last resort\nagent-browser wait 5000\n```\n\nWhen dealing with consistently slow websites, use `wait --load networkidle` after `open` to ensure the page is fully loaded before taking a snapshot. If a specific element is slow to render, wait for it directly with `wait <selector>` or `wait @ref`.\n\n## Session Management and Cleanup\n\nWhen running multiple agents or automations concurrently, always use named sessions to avoid conflicts:\n\n```bash\n# Each agent gets its own isolated session\nagent-browser --session agent1 open site-a.com\nagent-browser --session agent2 open site-b.com\n\n# Check active sessions\nagent-browser session list\n```\n\nAlways close your browser session when done to avoid leaked processes:\n\n```bash\nagent-browser close                    # Close default session\nagent-browser --session agent1 close   # Close specific session\n```\n\nIf a previous session was not closed properly, the daemon may still be running. Use `agent-browser close` to clean it up before starting new work.\n\n## Ref Lifecycle (Important)\n\nRefs (`@e1`, `@e2`, etc.) are invalidated when the page changes. Always re-snapshot after:\n\n- Clicking links or buttons that navigate\n- Form submissions\n- Dynamic content loading (dropdowns, modals)\n\n```bash\nagent-browser click @e5              # Navigates to new page\nagent-browser snapshot -i            # MUST re-snapshot\nagent-browser click @e1              # Use new refs\n```\n\n## Annotated Screenshots (Vision Mode)\n\nUse `--annotate` to take a screenshot with numbered labels overlaid on interactive elements. Each label `[N]` maps to ref `@eN`. This also caches refs, so you can interact with elements immediately without a separate snapshot.\n\n```bash\nagent-browser screenshot --annotate\n# Output includes the image path and a legend:\n#   [1] @e1 button \"Submit\"\n#   [2] @e2 link \"Home\"\n#   [3] @e3 textbox \"Email\"\nagent-browser click @e2              # Click using ref from annotated screenshot\n```\n\nUse annotated screenshots when:\n- The page has unlabeled icon buttons or visual-only elements\n- You need to verify visual layout or styling\n- Canvas or chart elements are present (invisible to text snapshots)\n- You need spatial reasoning about element positions\n\n## Semantic Locators (Alternative to Refs)\n\nWhen refs are unavailable or unreliable, use semantic locators:\n\n```bash\nagent-browser find text \"Sign In\" click\nagent-browser find label \"Email\" fill \"user@test.com\"\nagent-browser find role button click --name \"Submit\"\nagent-browser find placeholder \"Search\" type \"query\"\nagent-browser find testid \"submit-btn\" click\n```\n\n## JavaScript Evaluation (eval)\n\nUse `eval` to run JavaScript in the browser context. **Shell quoting can corrupt complex expressions** -- use `--stdin` or `-b` to avoid issues.\n\n```bash\n# Simple expressions work with regular quoting\nagent-browser eval 'document.title'\nagent-browser eval 'document.querySelectorAll(\"img\").length'\n\n# Complex JS: use --stdin with heredoc (RECOMMENDED)\nagent-browser eval --stdin <<'EVALEOF'\nJSON.stringify(\n  Array.from(document.querySelectorAll(\"img\"))\n    .filter(i => !i.alt)\n    .map(i => ({ src: i.src.split(\"/\").pop(), width: i.width }))\n)\nEVALEOF\n\n# Alternative: base64 encoding (avoids all shell escaping issues)\nagent-browser eval -b \"$(echo -n 'Array.from(document.querySelectorAll(\"a\")).map(a => a.href)' | base64)\"\n```\n\n**Why this matters:** When the shell processes your command, inner double quotes, `!` characters (history expansion), backticks, and `$()` can all corrupt the JavaScript before it reaches agent-browser. The `--stdin` and `-b` flags bypass shell interpretation entirely.\n\n**Rules of thumb:**\n- Single-line, no nested quotes -> regular `eval 'expression'` with single quotes is fine\n- Nested quotes, arrow functions, template literals, or multiline -> use `eval --stdin <<'EVALEOF'`\n- Programmatic/generated scripts -> use `eval -b` with base64\n\n## Configuration File\n\nCreate `agent-browser.json` in the project root for persistent settings:\n\n```json\n{\n  \"headed\": true,\n  \"proxy\": \"http://localhost:8080\",\n  \"profile\": \"./browser-data\"\n}\n```\n\nPriority (lowest to highest): `~/.agent-browser/config.json` < `./agent-browser.json` < env vars < CLI flags. Use `--config <path>` or `AGENT_BROWSER_CONFIG` env var for a custom config file (exits with error if missing/invalid). All CLI options map to camelCase keys (e.g., `--executable-path` -> `\"executablePath\"`). Boolean flags accept `true`/`false` values (e.g., `--headed false` overrides config). Extensions from user and project configs are merged, not replaced.\n\n## Deep-Dive Documentation\n\n| Reference | When to Use |\n|-----------|-------------|\n| [references/commands.md](references/commands.md) | Full command reference with all options |\n| [references/snapshot-refs.md](references/snapshot-refs.md) | Ref lifecycle, invalidation rules, troubleshooting |\n| [references/session-management.md](references/session-management.md) | Parallel sessions, state persistence, concurrent scraping |\n| [references/authentication.md](references/authentication.md) | Login flows, OAuth, 2FA handling, state reuse |\n| [references/video-recording.md](references/video-recording.md) | Recording workflows for debugging and documentation |\n| [references/profiling.md](references/profiling.md) | Chrome DevTools profiling for performance analysis |\n| [references/proxy-support.md](references/proxy-support.md) | Proxy configuration, geo-testing, rotating proxies |\n\n## Experimental: Native Mode\n\nagent-browser has an experimental native Rust daemon that communicates with Chrome directly via CDP, bypassing Node.js and Playwright entirely. It is opt-in and not recommended for production use yet.\n\n```bash\n# Enable via flag\nagent-browser --native open example.com\n\n# Enable via environment variable (avoids passing --native every time)\nexport AGENT_BROWSER_NATIVE=1\nagent-browser open example.com\n```\n\nThe native daemon supports Chromium and Safari (via WebDriver). Firefox and WebKit are not yet supported. All core commands (navigate, snapshot, click, fill, screenshot, cookies, storage, tabs, eval, etc.) work identically in native mode. Use `agent-browser close` before switching between native and default mode within the same session.\n\n## Ready-to-Use Templates\n\n| Template | Description |\n|----------|-------------|\n| [templates/form-automation.sh](templates/form-automation.sh) | Form filling with validation |\n| [templates/authenticated-session.sh](templates/authenticated-session.sh) | Login once, reuse state |\n| [templates/capture-workflow.sh](templates/capture-workflow.sh) | Content extraction with screenshots |\n\n```bash\n./templates/form-automation.sh https://example.com/form\n./templates/authenticated-session.sh https://app.example.com/login\n./templates/capture-workflow.sh https://example.com ./output\n```\n","frontmatter":{"name":"agent-browser","description":"Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to \"open a website\", \"fill out a form\", \"click a button\", \"take a screenshot\", \"scrape data from a page\", \"test this web app\", \"login to a site\", \"automate browser actions\", or any task requiring programmatic web interaction.","allowed-tools":"Bash(npx agent-browser:*), Bash(agent-browser:*)","allowedTools":["Bash(npx","agent-browser:*),","Bash(agent-browser:*)"]},"allowedTools":["Bash(npx","agent-browser:*),","Bash(agent-browser:*)"],"isInternal":false,"tokens":4372,"sizeBytes":19750},{"name":"SKILL.md","path":"src/resources/skills/api-design/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/api-design/SKILL.md","title":"api-design","category":"anthropic-skill","format":"markdown","content":"---\nname: api-design\ndescription: Design or review an HTTP/REST/GraphQL API for versioning, pagination, error shapes, idempotency, auth, and evolvability. Use when asked to \"design an API\", \"shape the endpoints\", \"design the schema\", \"add a new endpoint\", \"review this API\", or when building/modifying a public or internal HTTP surface. Complements `design-an-interface` (which is interface-agnostic) by covering HTTP-specific concerns like status codes, cache headers, and breaking-change management.\n---\n\n<objective>\nShape an HTTP or GraphQL API so callers get predictable, evolvable, and honest semantics. The deliverable is a concrete endpoint/schema sketch with: URL or operation names, method/verb, request shape, response shape, error shape, auth model, pagination strategy, and versioning stance. Optimize for \"clients that exist in 2 years\" over \"client that's easy to write today\".\n</objective>\n\n<context>\nGSD-2 has `design-an-interface` for general module-interface design; this skill is the HTTP/GraphQL specialization. REST and GraphQL carry baggage — status codes, verbs, nullability, pagination — that a generic interface-design discussion glosses over.\n\nInvocation points:\n- Adding a new public API endpoint\n- Redesigning an internal API boundary between services\n- Code review of a PR that introduces HTTP handlers\n- A slice whose acceptance criteria include \"the API works\"\n- A GraphQL schema change\n</context>\n\n<core_principle>\n**CALLERS OUTLIVE YOUR ASSUMPTIONS.** An API you ship today has to keep working when your internals change, when the mobile app version two is still in use, and when a third party integrates against it. Design for extension, not just for the current caller.\n\n**HONEST STATUS CODES.** 200 OK with `{\"error\": \"not found\"}` is a lie. 404 says not found. Use the HTTP semantics the protocol offers — HTTP clients, caches, and intermediaries rely on them.\n\n**PAGINATION IS NON-OPTIONAL.** Any list endpoint that doesn't paginate will eventually get a request for \"all records\" that kills your database.\n</core_principle>\n\n<process>\n\n## Step 1: Gather the contract\n\nAnswer, or ask (one round, 1–3 questions):\n\n1. **Who are the callers?** Internal service / mobile app / public third-party / same-repo frontend.\n2. **What's the versioning stance?** None / URL-path (`/v1/`) / header-based / GraphQL schema evolution.\n3. **Auth model?** Public / API key / OAuth / session cookie / mTLS / none-but-internal-only.\n4. **Idempotency expectation?** Is a retry safe? Required?\n5. **Consistency model?** Read-your-writes, eventual, serializable?\n\n## Step 2: Resource and operation naming\n\n### REST\n\n- Nouns not verbs in URLs: `POST /users`, not `POST /createUser`.\n- Plural resources: `/users/42`, not `/user/42`.\n- Nested only when the relationship is hierarchical and the child has no independent identity: `/users/42/sessions/3`. Otherwise flat: `/sessions/3?userId=42`.\n- Use subresources for actions that don't fit CRUD: `POST /users/42:deactivate` (colon syntax) or `POST /users/42/actions/deactivate`.\n\n### GraphQL\n\n- Queries are nouns; mutations are verbs: `user(id)`, `createUser(input)`, `deactivateUser(id)`.\n- Group related mutations under an input type: `createUser(input: CreateUserInput!)`.\n- Return the affected object plus any derived/computed fields from mutations — lets clients avoid a refetch.\n\n## Step 3: Methods and status codes\n\n### REST\n\n| Method | Intent | Idempotent? | Default success |\n|---|---|---|---|\n| GET | Read | Yes | 200, or 304 if conditional |\n| POST | Create or non-idempotent action | No | 201 with `Location` on create, 200 on action |\n| PUT | Replace (full-object) | Yes | 200 with body, or 204 |\n| PATCH | Partial update | No (usually) | 200 with body |\n| DELETE | Remove | Yes | 204 |\n\nErrors:\n- 400: caller screwed up the request shape\n- 401: no/invalid auth\n- 403: authed but not allowed\n- 404: resource doesn't exist\n- 409: conflict (version mismatch, unique constraint)\n- 410: gone (vs 404 when the resource previously existed and you want to signal that)\n- 422: validation failed\n- 429: rate-limited — include `Retry-After`\n- 500: genuinely unexpected server error\n- 503: service down or overloaded — include `Retry-After`\n\nNever 200-with-error-body. Never 500 for a 4xx cause.\n\n### GraphQL\n\n- Top-level errors (`errors[]`) for transport-level failures. Domain errors (validation, not-found, forbidden) go in the typed return — use a union or result type.\n- Partial results are expected; design the schema so `null` on a field is meaningful, not a signal of generic failure.\n\n## Step 4: Pagination\n\n- **Cursor-based by default.** Opaque cursor string, `limit`, return `nextCursor` when more exists. Scales, stable under writes.\n- **Offset-based only when:** dataset is small, user needs jump-to-page semantics (admin tables), and you're willing to accept stability drift.\n- **Never \"return everything\"** as default. Put a hard upper bound on `limit` (e.g., 200).\n- GraphQL: use Relay-style connections (`edges`, `pageInfo`) if the ecosystem expects it; otherwise a simpler `{items, nextCursor}` is fine.\n\n## Step 5: Error shape\n\nStandardize one shape and use it everywhere. Example REST:\n\n```json\n{\n  \"error\": {\n    \"code\": \"user_not_found\",\n    \"message\": \"No user with id 42\",\n    \"details\": { \"userId\": 42 },\n    \"requestId\": \"req_abc123\"\n  }\n}\n```\n\n- `code` is machine-readable; stable; documented.\n- `message` is human-readable; can change.\n- `details` carries structured context.\n- `requestId` lets callers report bugs.\n\nErrors don't leak stack traces, file paths, or internal queries.\n\n## Step 6: Idempotency, caching, concurrency\n\n- **Idempotency keys** for POST operations that mustn't double-execute on retry. Caller passes `Idempotency-Key: <uuid>`; server dedupes for a window.\n- **ETags** for GET + conditional updates (`If-Match` on PUT/PATCH).\n- **Cache-Control** on GETs that are safely cacheable.\n- **Optimistic concurrency:** when multiple writers collide, 409 with the current state. Don't silently clobber.\n\n## Step 7: Versioning and evolution\n\n- **Additive changes are free:** new optional fields, new endpoints, new optional query params.\n- **Breaking changes need a plan:** path-versioned (`/v2/`), sunset headers on `/v1/`, deprecation window communicated. Or, for GraphQL, `@deprecated` on fields with a migration note.\n- **Document the contract:** OpenAPI/GraphQL SDL. Keep it in the repo. Make it part of the PR that introduces the change.\n\n## Step 8: Review or write it up\n\nIf this is a review, produce findings in the same shape as `security-review` / `review` — file:line, category, recommendation.\n\nIf this is a new design, produce:\n\n```markdown\n## <API name>\n\n### Scope\n<what the API is for, who calls it>\n\n### Endpoints / Operations\n- `POST /users` — create user. Request: `{email, name}`. Response 201: `{id, email, name, createdAt}` + `Location: /users/<id>`. Errors: 409 email taken, 422 invalid.\n- ...\n\n### Auth\n<model + where to put the credential>\n\n### Pagination\n<cursor shape, max limit>\n\n### Error shape\n<one canonical shape>\n\n### Idempotency / concurrency\n<rules>\n\n### Versioning\n<stance + how breaking changes will be handled>\n\n### OpenAPI / SDL\n<link or inline>\n```\n\nAppend architectural decisions to `.gsd/DECISIONS.md`.\n\n</process>\n\n<anti_patterns>\n\n- **200 OK with `{\"error\": \"...\"}`.** Lies to caches, proxies, retry libraries.\n- **Unbounded list endpoints.** `GET /users` without a `limit` cap will bite you.\n- **Offset pagination at scale.** Drifts under writes; slow at high offsets.\n- **Free-form error messages with no code.** Machine callers can't branch on prose.\n- **Breaking changes in-place.** Callers break; versioning exists for a reason.\n- **Ignoring idempotency on retriable POSTs.** Double-charges, duplicate records.\n- **Auth checks at the handler only, not the service layer.** Defense in depth.\n\n</anti_patterns>\n\n<success_criteria>\n\n- [ ] Every endpoint/operation has named request, response, and error shapes.\n- [ ] Status codes match HTTP semantics — no 200-with-error.\n- [ ] List endpoints paginate; max limit is documented.\n- [ ] A single error shape is used everywhere, with a machine-readable code.\n- [ ] Versioning stance is stated — even if the answer is \"additive only for now.\"\n- [ ] OpenAPI/SDL reflects the design and lives in the repo.\n- [ ] Decisions appear in `.gsd/DECISIONS.md`.\n\n</success_criteria>\n","frontmatter":{"name":"api-design","description":"Design or review an HTTP/REST/GraphQL API for versioning, pagination, error shapes, idempotency, auth, and evolvability. Use when asked to \"design an API\", \"shape the endpoints\", \"design the schema\", \"add a new endpoint\", \"review this API\", or when building/modifying a public or internal HTTP surface. Complements `design-an-interface` (which is interface-agnostic) by covering HTTP-specific concerns like status codes, cache headers, and breaking-change management."},"isInternal":false,"tokens":2086,"sizeBytes":8391},{"name":"SKILL.md","path":"src/resources/skills/best-practices/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/best-practices/SKILL.md","title":"best-practices","category":"anthropic-skill","format":"markdown","content":"---\nname: best-practices\ndescription: Apply modern web development best practices for security, compatibility, and code quality. Use when asked to \"apply best practices\", \"security audit\", \"modernize code\", \"code quality review\", or \"check for vulnerabilities\".\nlicense: MIT\nmetadata:\n  author: web-quality-skills\n  version: \"1.0\"\n---\n\n# Best practices\n\nModern web development standards based on Lighthouse best practices audits. Covers security, browser compatibility, and code quality patterns.\n\n## Security\n\n### HTTPS everywhere\n\n**Enforce HTTPS:**\n```html\n<!-- ❌ Mixed content -->\n<img src=\"http://example.com/image.jpg\">\n<script src=\"http://cdn.example.com/script.js\"></script>\n\n<!-- ✅ HTTPS only -->\n<img src=\"https://example.com/image.jpg\">\n<script src=\"https://cdn.example.com/script.js\"></script>\n\n<!-- ✅ Protocol-relative (will use page's protocol) -->\n<img src=\"//example.com/image.jpg\">\n```\n\n**HSTS Header:**\n```\nStrict-Transport-Security: max-age=31536000; includeSubDomains; preload\n```\n\n### Content Security Policy (CSP)\n\n```html\n<!-- Basic CSP via meta tag -->\n<meta http-equiv=\"Content-Security-Policy\" \n      content=\"default-src 'self'; \n               script-src 'self' https://trusted-cdn.com; \n               style-src 'self' 'unsafe-inline';\n               img-src 'self' data: https:;\n               connect-src 'self' https://api.example.com;\">\n\n<!-- Better: HTTP header -->\n```\n\n**CSP Header (recommended):**\n```\nContent-Security-Policy: \n  default-src 'self';\n  script-src 'self' 'nonce-abc123' https://trusted.com;\n  style-src 'self' 'nonce-abc123';\n  img-src 'self' data: https:;\n  connect-src 'self' https://api.example.com;\n  frame-ancestors 'self';\n  base-uri 'self';\n  form-action 'self';\n```\n\n**Using nonces for inline scripts:**\n```html\n<script nonce=\"abc123\">\n  // This inline script is allowed\n</script>\n```\n\n### Security headers\n\n```\n# Prevent clickjacking\nX-Frame-Options: DENY\n\n# Prevent MIME type sniffing\nX-Content-Type-Options: nosniff\n\n# Enable XSS filter (legacy browsers)\nX-XSS-Protection: 1; mode=block\n\n# Control referrer information\nReferrer-Policy: strict-origin-when-cross-origin\n\n# Permissions policy (formerly Feature-Policy)\nPermissions-Policy: geolocation=(), microphone=(), camera=()\n```\n\n### No vulnerable libraries\n\n```bash\n# Check for vulnerabilities\nnpm audit\nyarn audit\n\n# Auto-fix when possible\nnpm audit fix\n\n# Check specific package\nnpm ls lodash\n```\n\n**Keep dependencies updated:**\n```json\n// package.json\n{\n  \"scripts\": {\n    \"audit\": \"npm audit --audit-level=moderate\",\n    \"update\": \"npm update && npm audit fix\"\n  }\n}\n```\n\n**Known vulnerable patterns to avoid:**\n```javascript\n// ❌ Prototype pollution vulnerable patterns\nObject.assign(target, userInput);\n_.merge(target, userInput);\n\n// ✅ Safer alternatives\nconst safeData = JSON.parse(JSON.stringify(userInput));\n```\n\n### Input sanitization\n\n```javascript\n// ❌ XSS vulnerable\nelement.innerHTML = userInput;\ndocument.write(userInput);\n\n// ✅ Safe text content\nelement.textContent = userInput;\n\n// ✅ If HTML needed, sanitize\nimport DOMPurify from 'dompurify';\nelement.innerHTML = DOMPurify.sanitize(userInput);\n```\n\n### Secure cookies\n\n```javascript\n// ❌ Insecure cookie\ndocument.cookie = \"session=abc123\";\n\n// ✅ Secure cookie (server-side)\nSet-Cookie: session=abc123; Secure; HttpOnly; SameSite=Strict; Path=/\n```\n\n---\n\n## Browser compatibility\n\n### Doctype declaration\n\n```html\n<!-- ❌ Missing or invalid doctype -->\n<HTML>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n\n<!-- ✅ HTML5 doctype -->\n<!DOCTYPE html>\n<html lang=\"en\">\n```\n\n### Character encoding\n\n```html\n<!-- ❌ Missing or late charset -->\n<html>\n<head>\n  <title>Page</title>\n  <meta charset=\"UTF-8\">\n</head>\n\n<!-- ✅ Charset as first element in head -->\n<html>\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Page</title>\n</head>\n```\n\n### Viewport meta tag\n\n```html\n<!-- ❌ Missing viewport -->\n<head>\n  <title>Page</title>\n</head>\n\n<!-- ✅ Responsive viewport -->\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <title>Page</title>\n</head>\n```\n\n### Feature detection\n\n```javascript\n// ❌ Browser detection (brittle)\nif (navigator.userAgent.includes('Chrome')) {\n  // Chrome-specific code\n}\n\n// ✅ Feature detection\nif ('IntersectionObserver' in window) {\n  // Use IntersectionObserver\n} else {\n  // Fallback\n}\n\n// ✅ Using @supports in CSS\n@supports (display: grid) {\n  .container {\n    display: grid;\n  }\n}\n\n@supports not (display: grid) {\n  .container {\n    display: flex;\n  }\n}\n```\n\n### Polyfills (when needed)\n\n```html\n<!-- Load polyfills conditionally -->\n<script>\n  if (!('fetch' in window)) {\n    document.write('<script src=\"/polyfills/fetch.js\"><\\/script>');\n  }\n</script>\n\n<!-- Or use polyfill.io -->\n<script src=\"https://polyfill.io/v3/polyfill.min.js?features=fetch,IntersectionObserver\"></script>\n```\n\n---\n\n## Deprecated APIs\n\n### Avoid these\n\n```javascript\n// ❌ document.write (blocks parsing)\ndocument.write('<script src=\"...\"></script>');\n\n// ✅ Dynamic script loading\nconst script = document.createElement('script');\nscript.src = '...';\ndocument.head.appendChild(script);\n\n// ❌ Synchronous XHR (blocks main thread)\nconst xhr = new XMLHttpRequest();\nxhr.open('GET', url, false); // false = synchronous\n\n// ✅ Async fetch\nconst response = await fetch(url);\n\n// ❌ Application Cache (deprecated)\n<html manifest=\"cache.manifest\">\n\n// ✅ Service Workers\nif ('serviceWorker' in navigator) {\n  navigator.serviceWorker.register('/sw.js');\n}\n```\n\n### Event listener passive\n\n```javascript\n// ❌ Non-passive touch/wheel (may block scrolling)\nelement.addEventListener('touchstart', handler);\nelement.addEventListener('wheel', handler);\n\n// ✅ Passive listeners (allows smooth scrolling)\nelement.addEventListener('touchstart', handler, { passive: true });\nelement.addEventListener('wheel', handler, { passive: true });\n\n// ✅ If you need preventDefault, be explicit\nelement.addEventListener('touchstart', handler, { passive: false });\n```\n\n---\n\n## Console & errors\n\n### No console errors\n\n```javascript\n// ❌ Errors in production\nconsole.log('Debug info'); // Remove in production\nthrow new Error('Unhandled'); // Catch all errors\n\n// ✅ Proper error handling\ntry {\n  riskyOperation();\n} catch (error) {\n  // Log to error tracking service\n  errorTracker.captureException(error);\n  // Show user-friendly message\n  showErrorMessage('Something went wrong. Please try again.');\n}\n```\n\n### Error boundaries (React)\n\n```jsx\nclass ErrorBoundary extends React.Component {\n  state = { hasError: false };\n  \n  static getDerivedStateFromError(error) {\n    return { hasError: true };\n  }\n  \n  componentDidCatch(error, info) {\n    errorTracker.captureException(error, { extra: info });\n  }\n  \n  render() {\n    if (this.state.hasError) {\n      return <FallbackUI />;\n    }\n    return this.props.children;\n  }\n}\n\n// Usage\n<ErrorBoundary>\n  <App />\n</ErrorBoundary>\n```\n\n### Global error handler\n\n```javascript\n// Catch unhandled errors\nwindow.addEventListener('error', (event) => {\n  errorTracker.captureException(event.error);\n});\n\n// Catch unhandled promise rejections\nwindow.addEventListener('unhandledrejection', (event) => {\n  errorTracker.captureException(event.reason);\n});\n```\n\n---\n\n## Source maps\n\n### Production configuration\n\n```javascript\n// ❌ Source maps exposed in production\n// webpack.config.js\nmodule.exports = {\n  devtool: 'source-map', // Exposes source code\n};\n\n// ✅ Hidden source maps (uploaded to error tracker)\nmodule.exports = {\n  devtool: 'hidden-source-map',\n};\n\n// ✅ Or no source maps in production\nmodule.exports = {\n  devtool: process.env.NODE_ENV === 'production' ? false : 'source-map',\n};\n```\n\n---\n\n## Performance best practices\n\n### Avoid blocking patterns\n\n```javascript\n// ❌ Blocking script\n<script src=\"heavy-library.js\"></script>\n\n// ✅ Deferred script\n<script defer src=\"heavy-library.js\"></script>\n\n// ❌ Blocking CSS import\n@import url('other-styles.css');\n\n// ✅ Link tags (parallel loading)\n<link rel=\"stylesheet\" href=\"styles.css\">\n<link rel=\"stylesheet\" href=\"other-styles.css\">\n```\n\n### Efficient event handlers\n\n```javascript\n// ❌ Handler on every element\nitems.forEach(item => {\n  item.addEventListener('click', handleClick);\n});\n\n// ✅ Event delegation\ncontainer.addEventListener('click', (e) => {\n  if (e.target.matches('.item')) {\n    handleClick(e);\n  }\n});\n```\n\n### Memory management\n\n```javascript\n// ❌ Memory leak (never removed)\nconst handler = () => { /* ... */ };\nwindow.addEventListener('resize', handler);\n\n// ✅ Cleanup when done\nconst handler = () => { /* ... */ };\nwindow.addEventListener('resize', handler);\n\n// Later, when component unmounts:\nwindow.removeEventListener('resize', handler);\n\n// ✅ Using AbortController\nconst controller = new AbortController();\nwindow.addEventListener('resize', handler, { signal: controller.signal });\n\n// Cleanup:\ncontroller.abort();\n```\n\n---\n\n## Code quality\n\n### Valid HTML\n\n```html\n<!-- ❌ Invalid HTML -->\n<div id=\"header\">\n<div id=\"header\"> <!-- Duplicate ID -->\n\n<ul>\n  <div>Item</div> <!-- Invalid child -->\n</ul>\n\n<a href=\"/\"><button>Click</button></a> <!-- Invalid nesting -->\n\n<!-- ✅ Valid HTML -->\n<header id=\"site-header\">\n</header>\n\n<ul>\n  <li>Item</li>\n</ul>\n\n<a href=\"/\" class=\"button\">Click</a>\n```\n\n### Semantic HTML\n\n```html\n<!-- ❌ Non-semantic -->\n<div class=\"header\">\n  <div class=\"nav\">\n    <div class=\"nav-item\">Home</div>\n  </div>\n</div>\n<div class=\"main\">\n  <div class=\"article\">\n    <div class=\"title\">Headline</div>\n  </div>\n</div>\n\n<!-- ✅ Semantic HTML5 -->\n<header>\n  <nav>\n    <a href=\"/\">Home</a>\n  </nav>\n</header>\n<main>\n  <article>\n    <h1>Headline</h1>\n  </article>\n</main>\n```\n\n### Image aspect ratios\n\n```html\n<!-- ❌ Distorted images -->\n<img src=\"photo.jpg\" width=\"300\" height=\"100\">\n<!-- If actual ratio is 4:3, this squishes the image -->\n\n<!-- ✅ Preserve aspect ratio -->\n<img src=\"photo.jpg\" width=\"300\" height=\"225\">\n<!-- Actual 4:3 dimensions -->\n\n<!-- ✅ CSS object-fit for flexibility -->\n<img src=\"photo.jpg\" style=\"width: 300px; height: 200px; object-fit: cover;\">\n```\n\n---\n\n## Permissions & privacy\n\n### Request permissions properly\n\n```javascript\n// ❌ Request on page load (bad UX, often denied)\nnavigator.geolocation.getCurrentPosition(success, error);\n\n// ✅ Request in context, after user action\nfindNearbyButton.addEventListener('click', async () => {\n  // Explain why you need it\n  if (await showPermissionExplanation()) {\n    navigator.geolocation.getCurrentPosition(success, error);\n  }\n});\n```\n\n### Permissions policy\n\n```html\n<!-- Restrict powerful features -->\n<meta http-equiv=\"Permissions-Policy\" \n      content=\"geolocation=(), camera=(), microphone=()\">\n\n<!-- Or allow for specific origins -->\n<meta http-equiv=\"Permissions-Policy\" \n      content=\"geolocation=(self 'https://maps.example.com')\">\n```\n\n---\n\n## Audit checklist\n\n### Security (critical)\n- [ ] HTTPS enabled, no mixed content\n- [ ] No vulnerable dependencies (`npm audit`)\n- [ ] CSP headers configured\n- [ ] Security headers present\n- [ ] No exposed source maps\n\n### Compatibility\n- [ ] Valid HTML5 doctype\n- [ ] Charset declared first in head\n- [ ] Viewport meta tag present\n- [ ] No deprecated APIs used\n- [ ] Passive event listeners for scroll/touch\n\n### Code quality\n- [ ] No console errors\n- [ ] Valid HTML (no duplicate IDs)\n- [ ] Semantic HTML elements used\n- [ ] Proper error handling\n- [ ] Memory cleanup in components\n\n### UX\n- [ ] No intrusive interstitials\n- [ ] Permission requests in context\n- [ ] Clear error messages\n- [ ] Appropriate image aspect ratios\n\n## Tools\n\n| Tool | Purpose |\n|------|---------|\n| `npm audit` | Dependency vulnerabilities |\n| [SecurityHeaders.com](https://securityheaders.com) | Header analysis |\n| [W3C Validator](https://validator.w3.org) | HTML validation |\n| Lighthouse | Best practices audit |\n| [Observatory](https://observatory.mozilla.org) | Security scan |\n\n## References\n\n- [MDN Web Security](https://developer.mozilla.org/en-US/docs/Web/Security)\n- [OWASP Top 10](https://owasp.org/www-project-top-ten/)\n- [Web Quality Audit](../web-quality-audit/SKILL.md)\n","frontmatter":{"name":"best-practices","description":"Apply modern web development best practices for security, compatibility, and code quality. Use when asked to \"apply best practices\", \"security audit\", \"modernize code\", \"code quality review\", or \"check for vulnerabilities\".","license":"MIT","metadata":{"author":"web-quality-skills","version":"1.0"}},"isInternal":false,"tokens":2955,"sizeBytes":12138},{"name":"SKILL.md","path":"src/resources/skills/btw/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/btw/SKILL.md","title":"btw","category":"anthropic-skill","format":"markdown","content":"---\nname: btw\ndescription: Ask a quick side question about your current work without derailing the main task. Answers from existing conversation context only — no tool calls, no file reads, single concise response. Use when you need a fast answer from what is already in this session.\n---\n\n<objective>\nAnswer a quick side question using only what is already present in the current conversation context. Do not read files, run commands, search, or use any tools. Give a single, concise response and return focus to the main work.\n</objective>\n\n<behavior>\n**This is a side question, not a task.**\n\n- Answer only from information already in the conversation (files read, decisions made, code seen, context established)\n- Do NOT use any tools — no Read, no Bash, no Grep, no Search\n- If the answer requires reading something new, say so briefly and suggest the user ask as a normal prompt instead\n- Keep the response short and direct — one to a few sentences unless the question genuinely needs more\n- Do not summarize the main work, ask follow-up questions, or offer to do anything else\n- After answering, stop — do not prompt for next steps\n</behavior>\n\n<quick_start>\nParse the argument after `/btw` as the question. Answer it directly from context.\n\nIf no argument is provided, ask: \"What did you want to know?\"\n\nIf the question cannot be answered from current context (requires reading a file, running a command, or information not yet in the session), respond with:\n\"I'd need to [read X / run Y / look up Z] to answer that — ask it as a normal prompt when you're ready.\"\n</quick_start>\n\n<examples>\n**Good uses of /btw:**\n- `/btw what was the name of that config file again?` → answers from files already read in session\n- `/btw which branch are we on?` → answers from git context already established\n- `/btw did we already handle the null case in that function?` → answers from code already reviewed\n- `/btw what model does this use?` → answers from code or config already in context\n\n**Not a good fit for /btw (suggest normal prompt):**\n- Questions requiring reading a file not yet seen\n- Questions requiring running a command\n- Questions needing a multi-step answer or follow-up\n- Starting a new task or changing direction\n</examples>\n","frontmatter":{"name":"btw","description":"Ask a quick side question about your current work without derailing the main task. Answers from existing conversation context only — no tool calls, no file reads, single concise response. Use when you need a fast answer from what is already in this session."},"isInternal":false,"tokens":502,"sizeBytes":2256},{"name":"algorithmic-complexity.md","path":"src/resources/skills/code-optimizer/references/algorithmic-complexity.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/references/algorithmic-complexity.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Algorithmic Complexity\n\n## Grep/Glob Patterns to Detect\n\n### O(n^2) and Worse Patterns\n```\n# Nested loops over same/related collections\nfor.*in.*\\n.*for.*in         (nested for loops)\n\\.forEach\\(.*\\.forEach\\(      (nested forEach)\n\\.map\\(.*\\.map\\(              (nested map)\n\\.filter\\(.*\\.includes\\(      (filter+includes = O(n*m))\n\\.find\\(.*inside.*\\.map\\(     (find inside map)\n\\.indexOf\\(.*inside.*for      (indexOf in loop)\n\\.includes\\(.*inside.*for     (includes in loop)\n# Array as lookup table\narray\\.find\\(.*===            (use Map/Set instead)\narray\\.some\\(.*===            (use Set.has instead)\nlist\\.index\\(                 (Python: use dict instead)\nif.*in\\s+list                 (Python: O(n) lookup in list)\n```\n\n### Unnecessary Iterations\n```\n\\.filter\\(.*\\.length          (filter just to count)\n\\.filter\\(.*\\[0\\]             (filter just to get first - use find)\n\\.map\\(.*\\.filter\\(           (map then filter - combine or reverse order)\n\\.filter\\(.*\\.map\\(.*\\.filter (multiple passes when one suffices)\n\\.sort\\(\\).*\\[0\\]             (sort to get min/max - use Math.min/max or reduce)\n\\.sort\\(\\).*\\.slice\\(0        (sort to get top-k - use partial sort/heap)\nsorted\\(.*\\)\\[0\\]             (Python: use min() instead)\nsorted\\(.*\\)\\[-1\\]            (Python: use max() instead)\n\\.reverse\\(\\).*\\.forEach      (reverse just to iterate backwards)\nObject\\.keys\\(.*\\.map\\(.*Object\\.values  (iterating keys then accessing values)\n```\n\n### Redundant Computation\n```\n# Same computation in loop\nfor.*\\n.*Math\\.              (math operations that could be hoisted)\nfor.*\\n.*\\.length            (accessing .length repeatedly - may be fine, check)\nfor.*\\n.*document\\.querySelector  (DOM queries in loops)\nfor.*\\n.*JSON\\.parse         (parsing same JSON repeatedly)\nfor.*\\n.*new RegExp\\(        (creating regex in loop)\nfor.*\\n.*new Date\\(          (creating Date objects in loop for same date)\n```\n\n### Inefficient Data Structure Choice\n```\n# Using arrays where Set/Map would be better\n\\.push\\(.*\\.includes\\(       (array as unique set)\n\\.filter\\(.*\\.indexOf\\(       (dedup with filter+indexOf)\n\\[\\].*\\.find\\(               (array for lookups)\n# Using objects where Map would be better\n\\{\\}.*\\[.*\\]\\s*=             (frequent dynamic key insertion)\ndelete.*\\[                   (frequent key deletion from object)\n```\n\n## Improvement Strategies\n\n1. **Nested loops**: Pre-build lookup Map/Set, use hash-based approaches\n2. **Filter+includes**: Convert one collection to Set for O(1) lookups\n3. **Sort for min/max**: Use Math.min/max, reduce, or heap for top-k\n4. **Multiple passes**: Combine into single reduce/loop\n5. **Redundant computation**: Hoist invariants out of loops, memoize\n6. **Array as lookup**: Use Map for key-value, Set for existence checks\n7. **String matching in loops**: Pre-compile regex, use Map for exact matches\n","isInternal":false,"tokens":749,"sizeBytes":2835},{"name":"build-compilation.md","path":"src/resources/skills/code-optimizer/references/build-compilation.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/references/build-compilation.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Build & Compilation Optimization\n\n## Grep/Glob Patterns to Detect\n\n### Unoptimized Build Config\n```\n# Webpack\nmode:\\s*['\"]development['\"]        (dev mode in production build)\ndevtool:\\s*['\"]source-map['\"]      (full source maps in production)\ndevtool:\\s*['\"]eval                (eval source maps in production)\n# No code splitting\nsplitChunks.*false                  (code splitting disabled)\n# No minification\nminimize:\\s*false                   (minification disabled)\n# Missing tree shaking\nsideEffects.*true                   (prevents tree shaking)\n```\n\n### Development-Only Code in Production\n```\nconsole\\.log\\(                     (debug logging)\nconsole\\.debug\\(                   (debug logging)\nconsole\\.trace\\(                   (trace logging)\ndebugger;                           (debugger statement)\n\\.only\\(                           (test.only left in)\n\\.skip\\(                           (test.skip left in)\nif\\s*\\(.*process\\.env\\.NODE_ENV.*development  (dev-only code)\n__DEV__                             (React Native dev flag)\n```\n\n### Missing Optimization Flags\n```\n# TypeScript\n\"strict\":\\s*false                  (strict mode disabled)\n\"skipLibCheck\":\\s*false            (slow lib checking)\n\"incremental\":\\s*false             (no incremental compilation)\n# Python\npython\\s+-O                        (check if optimized flag used)\n__debug__                           (debug-only code)\n# Docker\nFROM.*:latest                      (unpinned base image)\nRUN.*pip install(?!.*--no-cache)   (pip without --no-cache-dir)\nRUN.*npm install(?!.*--production) (npm install without --production)\nCOPY\\s+\\.\\s+\\.                     (copying entire context)\n```\n\n### Large/Slow Imports at Startup\n```\n# Top-level heavy imports that could be lazy\nimport.*tensorflow                  (heavy ML library at top)\nimport.*pandas                      (heavy data library at top)\nimport.*matplotlib                  (heavy viz library at top)\nimport.*scipy                       (heavy math library at top)\nfrom.*import\\s+\\*                   (wildcard imports slow startup)\n# Circular imports\nImportError.*circular               (circular import errors)\n```\n\n### Missing Caching in CI/CD\n```\n# No caching steps\nnpm install(?!.*cache)              (npm install without cache)\npip install(?!.*cache)              (pip install without cache)\ngo build(?!.*cache)                 (go build without cache)\ndocker build(?!.*cache)             (docker build without layer cache)\n```\n\n### Slow Test Suite\n```\n# Real I/O in tests\nfetch\\(.*test                       (real network calls in tests)\nrequests\\.\\w+\\(.*test              (real HTTP in Python tests)\nopen\\(.*test                        (real file I/O in tests)\n# No test parallelization\n--runInBand                         (Jest sequential mode)\n-p no:xdist                         (pytest parallelization disabled)\n# Heavy setup/teardown\nbeforeAll.*database                 (real DB setup in tests)\nsetUp.*database                     (real DB in Python tests)\n```\n\n## Improvement Strategies\n\n1. **Build config**: Ensure production mode, minification, tree shaking, code splitting\n2. **Dev code**: Strip console.log/debugger via build plugin (e.g., babel-plugin-transform-remove-console)\n3. **TypeScript**: Enable strict, incremental, skipLibCheck for faster builds\n4. **Docker**: Multi-stage builds, .dockerignore, layer caching, pinned versions\n5. **Lazy imports**: Move heavy imports to function scope where they're needed\n6. **CI caching**: Cache node_modules, pip cache, go build cache, Docker layers\n7. **Test speed**: Mock I/O, run tests in parallel, use in-memory DBs for integration tests\n","isInternal":false,"tokens":805,"sizeBytes":3650},{"name":"bundle-dependencies.md","path":"src/resources/skills/code-optimizer/references/bundle-dependencies.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/references/bundle-dependencies.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Bundle Size & Dependencies\n\n## Grep/Glob Patterns to Detect\n\n### Heavy Imports\n```\nimport\\s+\\w+\\s+from\\s+['\"]lodash['\"]      (full lodash import vs lodash/specific)\nimport\\s+\\w+\\s+from\\s+['\"]moment['\"]      (moment.js - use date-fns/dayjs)\nimport\\s+\\w+\\s+from\\s+['\"]underscore['\"]  (underscore - mostly native now)\nimport\\s+\\*\\s+as                           (wildcard imports prevent tree-shaking)\nrequire\\(['\"]lodash['\"]\\)                   (CJS lodash import)\nfrom\\s+pandas\\s+import\\s+\\*                (full pandas import)\nimport\\s+tensorflow                         (full TF import)\nimport\\s+boto3                              (full AWS SDK)\n```\n\n### Unused Dependencies\n```\n# Check package.json dependencies vs actual imports\n# Check requirements.txt vs actual imports\n# Check go.mod vs actual imports\nimport.*from.*['\"](\\w+)['\"]   (cross-reference with package.json)\n```\n\n### Duplicate Functionality\n```\n# Multiple date libraries\nmoment.*\\n.*date-fns          (both moment and date-fns)\nmoment.*\\n.*dayjs             (both moment and dayjs)\n# Multiple HTTP clients\naxios.*\\n.*node-fetch         (both axios and fetch)\naxios.*\\n.*got                (both axios and got)\n# Multiple utility libraries\nlodash.*\\n.*underscore        (both lodash and underscore)\n# Multiple state managers\nredux.*\\n.*mobx               (both redux and mobx)\nzustand.*\\n.*jotai            (multiple state libs)\n```\n\n### Dev Dependencies in Production\n```\n# devDependencies imported in src/\nimport.*from.*['\"](@testing|jest|mocha|chai|sinon|cypress|storybook)\n# Debug/test code in production\nconsole\\.log\\(\nconsole\\.debug\\(\ndebugger;\n\\.only\\(         (test.only left in)\n```\n\n### Dynamic Imports Missing\n```\n# Large components imported statically that could be lazy\nimport.*Modal       (modals are great candidates for lazy loading)\nimport.*Chart       (charts are heavy)\nimport.*Editor      (rich editors are heavy)\nimport.*PDF         (PDF libs are heavy)\nimport.*Map         (map components are heavy)\n# Route-level components not lazy loaded\nimport.*Page.*from  (page components should often be lazy)\n```\n\n### Large Assets\n```\n# Check for unoptimized assets\n\\.png['\"]          (check if could be webp/avif)\n\\.jpg['\"]          (check if could be webp/avif)\n\\.gif['\"]          (check if could be video/webp)\n\\.svg['\"].*import  (SVGs imported as modules - check size)\nbase64             (inline base64 assets)\ndata:image         (inline images)\n```\n\n## Improvement Strategies\n\n1. **Lodash**: Use `lodash-es/specific` or native equivalents (Array.find, Object.entries, etc.)\n2. **Moment.js**: Replace with date-fns or dayjs (10x smaller)\n3. **Wildcard imports**: Use named imports for tree-shaking\n4. **Unused deps**: Remove from package.json/requirements.txt\n5. **Dynamic imports**: Use React.lazy/import() for heavy, below-fold components\n6. **Images**: Convert to WebP/AVIF, use responsive srcset, lazy load below-fold\n7. **Duplicate libs**: Consolidate to one library per concern\n","isInternal":false,"tokens":740,"sizeBytes":2967},{"name":"caching-memoization.md","path":"src/resources/skills/code-optimizer/references/caching-memoization.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/references/caching-memoization.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Caching & Memoization\n\n## Grep/Glob Patterns to Detect\n\n### Missing Memoization\n```\n# Expensive computations without caching\ndef\\s+\\w+\\(.*\\).*:\\s*\\n.*for.*for      (Python: expensive function without @lru_cache)\nfunction\\s+\\w+\\(.*\\).*\\{.*for.*for     (JS: expensive function without memoization)\n# React missing useMemo/useCallback\nconst\\s+\\w+\\s*=\\s*\\w+\\.filter\\(        (derived data on every render)\nconst\\s+\\w+\\s*=\\s*\\w+\\.map\\(           (derived data on every render)\nconst\\s+\\w+\\s*=\\s*\\w+\\.reduce\\(        (derived data on every render)\nconst\\s+\\w+\\s*=\\s*\\w+\\.sort\\(          (sorting on every render)\n# Same computation called multiple times\n(\\w+)\\(same_args\\).*\\1\\(same_args\\)    (same function, same args, called twice)\n```\n\n### Cache Without Invalidation\n```\ncache\\s*=\\s*\\{\\}                        (cache without TTL or max size)\n_cache\\s*=\\s*\\{\\}                       (module cache without eviction)\nmemo\\s*=\\s*\\{\\}                         (memo without invalidation)\n\\.cache\\s*=\\s*\\{\\}                      (instance cache without cleanup)\nCACHE_TTL.*=.*(?:86400|3600.*24)       (very long TTL - stale data risk)\n```\n\n### Redundant API/DB Calls\n```\n# Same query executed multiple times\n\\.query\\(.*same.*\\.query\\(             (duplicate queries)\nfetch\\(['\"]same_url['\"]\\).*fetch\\(     (duplicate fetches)\n# No SWR/stale-while-revalidate\nuseEffect\\(.*fetch\\(.*\\[\\]            (fetch on every mount without caching)\nuseEffect\\(.*axios\\.\\w+\\(.*\\[\\]       (API call on every mount)\ncomponentDidMount.*fetch               (fetch without caching layer)\n```\n\n### Over-Caching\n```\n# Caching things that change frequently\ncache.*user.*session                   (caching session-specific data)\ncache.*real.?time                      (caching real-time data)\ncache.*current.*time                   (caching time-dependent data)\n# Caching large objects\ncache\\[.*\\]\\s*=\\s*.*large             (large objects in cache)\n```\n\n### Missing HTTP Caching\n```\n# API responses without cache headers\nres\\.json\\(                            (check if Cache-Control is set)\nreturn\\s+Response\\(                    (check if cache headers are set)\nreturn\\s+JsonResponse\\(               (Django: check cache headers)\n# Static assets without long cache\nexpress\\.static\\(                      (check maxAge setting)\nnginx.*location.*static               (check expires/cache-control)\n```\n\n### Computed Properties Recalculated\n```\n# Getters that compute on every access\nget\\s+\\w+\\(\\)\\s*\\{.*return.*\\.filter   (getter computing on each access)\nget\\s+\\w+\\(\\)\\s*\\{.*return.*\\.map      (getter computing on each access)\n@property\\s*\\n\\s*def.*\\n.*for          (Python property computing in loop)\n```\n\n## Improvement Strategies\n\n1. **Memoization**: Use @lru_cache (Python), useMemo/useCallback (React), _.memoize (JS)\n2. **Cache invalidation**: Always set TTL and max size; prefer LRU eviction\n3. **API caching**: Use SWR/React Query for client, Redis/Memcached for server\n4. **HTTP caching**: Set Cache-Control headers, use ETags, stale-while-revalidate\n5. **Computed properties**: Cache results with dirty flag or use memoized selectors (reselect)\n6. **Request deduplication**: Deduplicate identical in-flight requests\n7. **Multi-level cache**: L1 (in-memory) -> L2 (Redis) -> L3 (DB) for read-heavy workloads\n","isInternal":false,"tokens":845,"sizeBytes":3287},{"name":"concurrency-async.md","path":"src/resources/skills/code-optimizer/references/concurrency-async.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/references/concurrency-async.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Concurrency & Async Patterns\n\n## Grep/Glob Patterns to Detect\n\n### Sequential Async (Should Be Parallel)\n```\nawait.*\\n.*await.*\\n.*await    (multiple sequential awaits that could be parallel)\nfor.*await                      (sequential await in loop)\n\\.then\\(.*\\.then\\(.*\\.then\\(   (promise chain that could be Promise.all)\n# Python\nawait.*\\n.*await.*\\n.*await    (sequential awaits)\nfor.*in.*:\\n.*await            (await in loop)\n```\n\n### Missing Parallelization\n```\n# Should use Promise.all / asyncio.gather\nfetch\\(.*\\n.*fetch\\(           (sequential fetches)\naxios\\.\\w+\\(.*\\n.*axios\\.     (sequential HTTP calls)\nrequests\\.\\w+\\(.*\\n.*requests\\. (Python sequential requests)\n```\n\n### Blocking Operations in Async Context\n```\n# Node.js sync operations in async code\nfs\\.readFileSync               (blocking file read)\nfs\\.writeFileSync              (blocking file write)\nfs\\.existsSync                 (blocking existence check)\nchild_process\\.execSync        (blocking exec)\n\\.readFileSync\\(               (any sync file operation)\n# Python blocking in async\ntime\\.sleep\\(                  (use asyncio.sleep instead)\nrequests\\.                     (use aiohttp/httpx instead)\nopen\\(.*\\.read\\(\\)            (use aiofiles instead)\nos\\.path\\.exists               (use aio equivalent)\n```\n\n### Race Conditions & Thread Safety\n```\n# Shared mutable state\nglobal\\s+\\w+.*=               (Python global mutation)\nthreading\\.Thread.*shared      (shared state across threads)\n# Missing locks\n\\.append\\(.*thread             (list append without lock)\n\\+=.*without.*lock             (increment without lock)\n# JavaScript\nlet\\s+\\w+.*=.*\\n.*async       (mutable let used in async)\n```\n\n### Unbounded Concurrency\n```\n# No concurrency limit\n\\.map\\(.*fetch                 (unbounded parallel fetches)\n\\.map\\(.*axios                 (unbounded parallel requests)\nPromise\\.all\\(.*\\.map\\(        (all items in parallel, no limit)\nasyncio\\.gather\\(.*for         (all coroutines at once)\n# Missing backpressure\nwhile.*true.*await             (infinite async loop without backpressure)\n```\n\n### Error Handling in Async\n```\n# Unhandled rejections\n\\.then\\(.*without.*\\.catch     (promise without catch)\nasync.*without.*try.*catch     (async without error handling)\n# Swallowed errors\ncatch\\s*\\(\\s*\\)\\s*\\{          (empty catch block)\nexcept:\\s*$                    (bare except)\nexcept\\s+Exception\\s*:.*pass  (catch-all with pass)\n```\n\n## Improvement Strategies\n\n1. **Sequential awaits**: Use Promise.all/allSettled, asyncio.gather for independent operations\n2. **Await in loops**: Batch with Promise.all or use p-limit for controlled concurrency\n3. **Blocking in async**: Replace sync APIs with async equivalents\n4. **Race conditions**: Use locks, atomic operations, or immutable patterns\n5. **Unbounded concurrency**: Use semaphores, p-limit, connection pools\n6. **Error handling**: Always catch async errors, use Promise.allSettled for partial failure tolerance\n7. **Backpressure**: Use queues, streaming, or batching for producer-consumer patterns\n","isInternal":false,"tokens":714,"sizeBytes":3032},{"name":"config-infra.md","path":"src/resources/skills/code-optimizer/references/config-infra.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/references/config-infra.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Configuration & Infrastructure Inefficiencies\n\n## Grep/Glob Patterns to Detect\n\n### Missing Connection Pooling\n```\n# New connection per request\ncreate_engine\\(.*(?!.*pool)        (SQLAlchemy without pool config)\nnew Pool\\(.*(?!.*max)              (pg Pool without max connections)\nmongoose\\.connect\\(.*(?!.*pool)    (Mongoose without pool)\nDriverManager\\.getConnection\\(     (Java: new connection per call)\npsycopg2\\.connect\\(.*(?!.*pool)   (psycopg2 without pool)\nredis\\.createClient\\(.*per.*request (new Redis client per request)\n```\n\n### Missing Environment-Based Config\n```\nhardcoded.*url                     (hardcoded URLs)\n['\"]http://localhost               (hardcoded localhost URLs)\n['\"]127\\.0\\.0\\.1                   (hardcoded localhost IPs)\npassword\\s*=\\s*['\"]                (hardcoded passwords)\napi.?key\\s*=\\s*['\"]               (hardcoded API keys)\nsecret\\s*=\\s*['\"]                  (hardcoded secrets)\nport\\s*=\\s*\\d{4}                   (hardcoded port numbers)\n```\n\n### Missing Process Management\n```\n# Single-threaded Node.js without clustering\napp\\.listen\\(.*(?!.*cluster)       (Node without cluster module)\n# Python without proper WSGI/ASGI workers\n\\.run\\(.*debug=True                (Flask debug mode)\nuvicorn\\.run\\(.*workers=1          (single worker)\ngunicorn.*-w\\s*1\\b                 (single gunicorn worker)\n```\n\n### Docker/Container Issues\n```\nFROM.*:latest                      (unpinned image version)\nRUN.*apt-get.*&&.*apt-get         (check if apt cache is cleaned)\nCOPY\\s+\\.\\s+\\.                     (copying entire context - no .dockerignore)\nRUN.*npm install\\b(?!.*--production) (installing devDeps in production)\nRUN.*pip install\\b(?!.*--no-cache) (pip without cache clearing)\n# Multiple RUN commands that should be combined\nRUN.*\\nRUN.*\\nRUN                  (multiple RUN layers)\n```\n\n### Missing Health Checks\n```\n# Services without health endpoints\napp\\.(listen|start)\\(.*(?!.*health) (server without health check)\n# Docker without HEALTHCHECK\nDockerfile.*(?!.*HEALTHCHECK)       (Dockerfile without health check)\n```\n\n### Inefficient Polling\n```\nsetInterval\\(.*fetch               (polling instead of WebSocket/SSE)\nsetInterval\\(.*axios               (polling instead of push)\nwhile.*sleep.*fetch                 (polling loop)\ntime\\.sleep\\(.*requests            (Python: polling with sleep)\n```\n\n## Improvement Strategies\n\n1. **Connection pooling**: Configure pool_size, max_overflow, pool_recycle\n2. **Environment config**: Use .env files, config libraries, never hardcode secrets\n3. **Process management**: Use cluster mode (Node), multiple workers (Python ASGI/WSGI)\n4. **Docker**: Multi-stage builds, .dockerignore, combine RUN layers, pin versions\n5. **Health checks**: Add /health endpoint, Docker HEALTHCHECK, readiness/liveness probes\n6. **Polling -> Push**: Use WebSocket, SSE, or long-polling instead of interval polling\n","isInternal":false,"tokens":698,"sizeBytes":2877},{"name":"data-structures.md","path":"src/resources/skills/code-optimizer/references/data-structures.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/references/data-structures.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Data Structures & Serialization\n\n## Grep/Glob Patterns to Detect\n\n### Wrong Data Structure for the Job\n```\n# Array used for frequent lookups (should be Map/Set/dict)\n\\.find\\(.*===                  (linear search - use Map)\n\\.findIndex\\(.*===             (linear search for index)\n\\.includes\\(.*inside.*loop     (O(n) lookup in loop)\n\\.indexOf\\(.*inside.*loop      (O(n) lookup in loop)\nif.*in\\s+\\[                    (Python: list membership test)\nlist\\.count\\(                  (Python: counting in list)\n\n# Searching sorted data linearly (should use binary search)\n\\.find\\(.*sorted               (linear search on sorted array)\nfor.*sorted                    (iterating sorted data to find)\n\n# Using objects where Map is better (non-string keys, frequent add/delete)\n\\w+\\[\\w+\\.id\\]\\s*=             (object with dynamic keys from IDs)\ndelete\\s+\\w+\\[                 (frequent deletion from object)\nObject\\.keys\\(.*\\.length       (counting object keys - Map.size is O(1))\n\n# Using array for queue/deque operations\n\\.shift\\(\\)                    (Array.shift is O(n) - use proper queue)\n\\.unshift\\(                    (Array.unshift is O(n))\n```\n\n### Unnecessary Deep Copies\n```\nJSON\\.parse\\(JSON\\.stringify    (JSON round-trip for deep clone)\n\\.map\\(.*\\.map\\(.*spread       (nested spread for deep copy)\n\\{\\.\\.\\..*\\{\\.\\.\\.             (nested object spread)\nstructuredClone\\(.*inside.*loop (deep cloning in loop)\ncopy\\.deepcopy\\(.*loop         (Python deepcopy in loop)\nimport\\s+copy                  (check if deepcopy is overused)\n```\n\n### Inefficient Serialization\n```\n# JSON for internal communication (use binary formats)\nJSON\\.stringify.*JSON\\.parse.*internal\npickle\\.dump.*pickle\\.load     (Python: consider msgpack for cross-language)\n# Serializing more than needed\nJSON\\.stringify\\(.*entire      (serializing entire object when subset needed)\n\\.toJSON\\(\\)                   (check what's being serialized)\n# Repeated serialization\nJSON\\.stringify\\(.*loop        (stringifying in loop)\nJSON\\.parse\\(.*loop            (parsing in loop)\n```\n\n### Unnecessary Object Creation\n```\nnew Date\\(.*inside.*loop       (creating Date objects in loop)\nnew RegExp\\(.*inside.*loop     (compiling regex in loop)\nnew URL\\(.*inside.*loop        (creating URL objects in loop)\n\\.split\\(.*\\.join\\(            (split then join - use replace)\n\\.toString\\(\\).*\\.split\\(      (unnecessary string conversion)\nArray\\.from\\(.*Array\\.from\\(   (double Array.from)\n```\n\n### Immutability Overhead\n```\n# Excessive spread operators\n\\{\\.\\.\\.state,                 (spreading large state objects)\n\\[\\.\\.\\.array,                 (spreading large arrays)\n\\.map\\(.*=>.*\\{\\.\\.\\.         (creating new objects in map with spread)\n# Immer not used where it should be\nproduce\\(                      (check if immer is used consistently)\n```\n\n## Improvement Strategies\n\n1. **Array -> Map/Set**: Use Map for key-value lookups, Set for membership testing\n2. **Array.shift/unshift**: Use a proper deque/queue implementation\n3. **Deep copies**: Use structuredClone (modern), or targeted shallow copies\n4. **Serialization**: Use msgpack/protobuf for internal services, only JSON for external APIs\n5. **Object creation in loops**: Hoist object creation, reuse instances, use object pools\n6. **Large state spreads**: Use Immer's produce(), or targeted updates\n7. **Binary search**: Use on sorted data instead of linear search\n","isInternal":false,"tokens":813,"sizeBytes":3386},{"name":"database-queries.md","path":"src/resources/skills/code-optimizer/references/database-queries.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/references/database-queries.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Database & Query Optimization\n\n## Grep/Glob Patterns to Detect\n\n### N+1 Query Problems\n```\n# ORM loops - querying inside iterations\nfor.*in.*\\.all\\(\\)\nfor.*in.*\\.filter\\(\nfor.*in.*\\.objects\\.\n\\.prefetch_related  (absence of - check if loops exist WITHOUT prefetch)\n\\.select_related    (absence of - check if FK access exists WITHOUT select_related)\n# SQLAlchemy\nsession\\.query.*for.*in\n\\.lazy\\s*=\\s*True\n# ActiveRecord\n\\.each.*\\.where\n\\.map.*\\.find\n# Sequelize / TypeORM\nfindOne.*inside.*map\nfindOne.*inside.*for\nawait.*find.*inside.*loop\n```\n\n### Unoptimized Queries\n```\nSELECT \\*\nSELECT.*FROM.*WITHOUT.*WHERE  (full table scans)\nLIKE '%           (leading wildcard - can't use index)\nORDER BY.*RAND()\nNOT IN.*SELECT     (subquery instead of JOIN)\nDISTINCT.*SELECT \\*\nGROUP BY.*without.*index\n\\.raw\\(.*SELECT    (raw queries - potential SQL injection too)\nCOUNT\\(\\*\\).*WHERE  (count with filter vs indexed count)\n```\n\n### Missing Indexes (Heuristic)\n```\nWHERE.*=.*AND.*=    (composite queries without composite index)\nORDER BY.*multiple columns\nJOIN.*ON.*without index hint\n\\.filter\\(.*__in=   (IN queries on large sets)\n```\n\n### ORM Anti-patterns\n```\n\\.save\\(\\).*inside.*loop    (batch update instead)\n\\.create\\(\\).*inside.*loop  (bulk_create instead)\n\\.update\\(\\).*for.*in       (queryset.update instead)\nlen\\(.*\\.all\\(\\)\\)          (.count() instead)\nlist\\(.*\\.all\\(\\)\\)         (unnecessary materialization)\nif.*\\.exists\\(\\).*\\.first\\(\\)  (double query)\n\\.values\\(\\).*\\.values\\(\\)     (chained values)\n```\n\n### Connection Management\n```\n# Missing connection pooling\ncreate_engine\\(.*pool_size  (check if pool is configured)\nnew Pool\\(                   (check pool settings)\nmax_connections             (check if reasonable)\n# Unclosed connections\nconnection\\.open.*without.*close\ncursor.*without.*close\n```\n\n## Improvement Strategies\n\n1. **N+1 Queries**: Use eager loading (prefetch_related, select_related, JOIN FETCH, include/eager)\n2. **SELECT ***: Select only needed columns\n3. **Missing indexes**: Add indexes on frequently filtered/joined columns\n4. **Loop queries**: Use bulk operations (bulk_create, bulk_update, executemany)\n5. **Connection pooling**: Configure connection pools with appropriate size\n6. **Query caching**: Cache frequently-read, rarely-changing data\n7. **Pagination**: Never load unbounded result sets\n","isInternal":false,"tokens":603,"sizeBytes":2336},{"name":"dead-code-redundancy.md","path":"src/resources/skills/code-optimizer/references/dead-code-redundancy.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/references/dead-code-redundancy.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Dead Code & Redundancy\n\n## Grep/Glob Patterns to Detect\n\n### Unused Exports/Functions\n```\nexport\\s+(function|const|class)\\s+\\w+    (cross-reference: is it imported anywhere?)\ndef\\s+\\w+\\(                              (cross-reference: is it called anywhere?)\npublic\\s+(static\\s+)?\\w+\\s+\\w+\\(        (Java/C# methods - are they called?)\nfunc\\s+\\w+\\(                             (Go functions - are they called?)\n```\n\n### Unused Imports\n```\nimport.*from.*['\"].*['\"]    (cross-reference with usage in file)\nfrom\\s+\\w+\\s+import\\s+\\w+  (Python: check if imported name is used)\nrequire\\(['\"].*['\"]\\)       (CJS: check if result is used)\nuse\\s+\\w+;                  (Rust: check if used)\n```\n\n### Commented-Out Code\n```\n//\\s*(function|const|let|var|class|import|return|if|for|while)\n#\\s*(def|class|import|return|if|for|while)\n/\\*[\\s\\S]*?(function|class|import)[\\s\\S]*?\\*/\n```\n\n### Dead Branches\n```\nif\\s*\\(\\s*false\\s*\\)        (always-false condition)\nif\\s*\\(\\s*true\\s*\\)         (always-true condition - dead else)\nif\\s*\\(\\s*0\\s*\\)            (falsy constant)\nif\\s*\\(\\s*['\"]['\"]          (empty string - always falsy)\nTODO.*remove                 (TODOs indicating dead code)\nFIXME.*remove\nHACK.*temporary\n# Feature flags stuck off\nFEATURE_.*=\\s*false\nENABLE_.*=\\s*false\n```\n\n### Duplicate Logic\n```\n# Similar function signatures in same file or nearby files\nfunction\\s+\\w*(get|fetch|load|process|handle)\\w*\\(   (many similar handlers)\ndef\\s+\\w*(get|fetch|load|process|handle)\\w*\\(        (Python: similar functions)\n# Copy-paste indicators\n# Same code block appearing multiple times (use Grep to find identical blocks)\n```\n\n### Deprecated/Legacy Code\n```\n@deprecated\n@Deprecated\n# deprecated\n\\.deprecated\nDEPRECATED\nlegacy\nLegacy\nLEGACY\n__legacy__\n_old\\b\n_backup\\b\n_v[0-9]\\b       (versioned functions like process_v1)\n```\n\n### Unreachable Code\n```\nreturn.*\\n\\s*(var|let|const|function)   (code after return)\nthrow.*\\n\\s*(var|let|const|function)    (code after throw)\nexit\\(\\).*\\n                            (code after exit)\nsys\\.exit\\(.*\\n                         (Python: code after sys.exit)\nbreak\\s*;\\s*\\n\\s*\\w                     (code after break)\n```\n\n## Improvement Strategies\n\n1. **Unused exports**: Remove and verify no external consumers (check all import statements)\n2. **Unused imports**: Remove with IDE or linting tooling\n3. **Commented code**: Delete it - version control preserves history\n4. **Dead branches**: Remove unreachable code, clean up feature flags\n5. **Duplicate logic**: Extract shared function, use strategy pattern if variants differ slightly\n6. **Deprecated code**: Plan migration, remove after all callers are updated\n7. **Unreachable code**: Remove statements after return/throw/exit\n","isInternal":false,"tokens":743,"sizeBytes":2715},{"name":"error-resilience.md","path":"src/resources/skills/code-optimizer/references/error-resilience.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/references/error-resilience.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Error Handling & Resilience\n\n## Grep/Glob Patterns to Detect\n\n### Missing Timeouts\n```\nfetch\\(.*(?!.*timeout)         (fetch without timeout)\naxios\\.\\w+\\(.*(?!.*timeout)   (axios without timeout)\nrequests\\.\\w+\\(.*(?!.*timeout) (Python requests without timeout)\nhttp\\.\\w+\\(.*(?!.*timeout)    (http call without timeout)\nnew Promise\\(.*(?!.*setTimeout) (promise without timeout)\n\\.connect\\(.*(?!.*timeout)     (DB/socket connect without timeout)\n```\n\n### Swallowed Errors\n```\ncatch\\s*\\(\\s*\\w*\\s*\\)\\s*\\{\\s*\\}  (empty catch block)\ncatch\\s*\\(\\s*\\)\\s*\\{\\s*\\}        (empty catch, no error param)\nexcept:\\s*$                        (bare except)\nexcept\\s+Exception.*pass          (catch-all with pass)\nexcept\\s+Exception.*continue      (catch-all with continue)\n\\.catch\\(\\s*\\(\\)\\s*=>\\s*\\{\\s*\\}\\) (empty .catch handler)\n\\.catch\\(\\s*\\(\\)\\s*=>\\s*null\\)    (swallowing with null)\non_error.*pass                     (error handler that does nothing)\n```\n\n### Missing Retries for Transient Failures\n```\n# Network calls without retry logic\nfetch\\(.*(?!.*retry)           (fetch without retry)\naxios\\.\\w+\\(.*(?!.*retry)     (API call without retry)\nrequests\\.\\w+\\(.*(?!.*retry)  (Python request without retry)\n# Database operations without retry\n\\.query\\(.*(?!.*retry)         (DB query without retry)\n\\.execute\\(.*(?!.*retry)       (DB execute without retry)\n```\n\n### No Circuit Breaker\n```\n# Repeated calls to potentially failing services without circuit breaking\nwhile.*retry.*fetch            (retry loop without circuit break)\nMAX_RETRIES.*=.*[5-9]|[1-9]\\d+ (high retry count without circuit breaker)\n```\n\n### Resource Cleanup on Error\n```\n# try without finally for resource cleanup\ntry\\s*\\{.*open.*(?!.*finally)   (open resource without finally)\ntry:.*open\\(.*(?!.*finally)     (Python: open without finally or context manager)\n# Async cleanup missing\nasync.*try.*(?!.*finally)       (async operation without cleanup)\n```\n\n### Cascading Failures\n```\n# No fallback/default values\n\\?\\?.*undefined                 (check fallback quality)\n\\|\\|.*null                      (check fallback quality)\n\\.get\\(.*,\\s*None\\)            (Python: check if None is appropriate default)\n# No graceful degradation\ncatch.*throw                    (catching just to re-throw - no degradation)\ncatch.*return\\s+null            (returning null on error - caller may not handle)\n```\n\n### Logging Without Action\n```\nconsole\\.error\\(.*(?!.*throw|return|retry)  (logging error but not handling it)\nlogger\\.error\\(.*(?!.*raise|return|retry)   (Python: logging without action)\nprint\\(.*error.*(?!.*raise|return)          (print error without handling)\n```\n\n## Improvement Strategies\n\n1. **Timeouts**: Add timeouts to ALL external calls (network, DB, file I/O). Use AbortController for fetch\n2. **Swallowed errors**: At minimum log errors, prefer explicit handling or re-throwing\n3. **Retries**: Implement exponential backoff with jitter for transient failures\n4. **Circuit breakers**: Use circuit breaker pattern for external service calls\n5. **Resource cleanup**: Use try-finally, context managers, or using statements\n6. **Graceful degradation**: Return cached/default data instead of failing completely\n7. **Error propagation**: Don't catch errors you can't handle - let them bubble up\n","isInternal":false,"tokens":820,"sizeBytes":3254},{"name":"io-network.md","path":"src/resources/skills/code-optimizer/references/io-network.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/references/io-network.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# I/O & Network Optimization\n\n## Grep/Glob Patterns to Detect\n\n### Sequential Requests (Should Be Batched/Parallel)\n```\nfetch\\(.*\\n.*fetch\\(           (sequential fetch calls)\naxios\\.\\w+\\(.*\\n.*axios\\.     (sequential axios calls)\nrequests\\.\\w+\\(.*\\n.*requests (sequential Python requests)\nhttp\\.\\w+\\(.*\\n.*http\\.       (sequential Node http calls)\n\\.get\\(.*\\n.*\\.get\\(           (sequential GET requests)\n\\.post\\(.*\\n.*\\.post\\(         (sequential POST requests)\n```\n\n### Missing Batching\n```\n# Individual API calls in loops\nfor.*\\n.*fetch\\(               (fetch in loop)\nfor.*\\n.*axios\\.               (axios in loop)\nfor.*\\n.*requests\\.            (requests in loop)\n\\.map\\(.*fetch                 (map with individual fetches)\n\\.forEach\\(.*fetch             (forEach with individual fetches)\n# Individual DB writes in loops\n\\.save\\(\\).*for                (save in loop - should batch)\n\\.insert\\(.*for                (insert in loop - should bulk insert)\n```\n\n### No Request Deduplication\n```\n# Same endpoint called multiple times\nfetch\\(['\"]([^'\"]+)['\"]\\)      (check for duplicate URLs)\naxios\\.\\w+\\(['\"]([^'\"]+)['\"]  (check for duplicate URLs)\nuseQuery\\(.*['\"]([^'\"]+)['\"]  (check for duplicate query keys)\n```\n\n### Missing Compression\n```\n# Large payload without compression\nContent-Type.*application/json  (check if gzip/br enabled)\nres\\.json\\(                     (response without compression middleware)\n# No compression middleware\nexpress\\(\\).*without.*compression\n```\n\n### Inefficient Serialization\n```\nJSON\\.stringify\\(.*large        (stringifying large objects)\nJSON\\.parse\\(.*JSON\\.stringify  (deep clone via JSON - use structuredClone)\npickle\\.dumps\\(                 (Python: consider msgpack/protobuf for performance)\nyaml\\.dump\\(.*yaml\\.load\\(     (YAML round-trip - slow for data exchange)\n```\n\n### Missing Streaming\n```\n\\.readFile\\(                   (read entire file vs createReadStream)\n\\.readFileSync\\(               (sync + entire file)\nbody\\.json\\(\\)                 (parse entire body vs streaming parser)\n\\.text\\(\\)                     (entire response as text)\n\\.json\\(\\).*large              (entire JSON response in memory)\nresponse\\.data                 (entire response buffered)\n```\n\n### Missing Caching Headers\n```\n# API responses without caching\nres\\.json\\(.*without.*cache-control\nres\\.send\\(.*without.*etag\n# Static assets without cache headers\nexpress\\.static\\(.*without.*maxAge\n```\n\n### Retry Without Backoff\n```\nretry.*count                   (check if exponential backoff exists)\nwhile.*retry                   (retry loop without delay increase)\ncatch.*retry                   (catch-retry without backoff)\nMAX_RETRIES                    (check backoff strategy)\n```\n\n## Improvement Strategies\n\n1. **Sequential requests**: Use Promise.all, asyncio.gather, or batch APIs\n2. **Loop requests**: Batch into single API call or use DataLoader pattern\n3. **Deduplication**: Use request deduplication (SWR, React Query, custom cache)\n4. **Compression**: Enable gzip/brotli at server and CDN level\n5. **Serialization**: Use efficient formats (protobuf, msgpack) for internal services\n6. **Streaming**: Use streams for large files/responses, NDJSON for large JSON\n7. **Caching**: Set appropriate Cache-Control, ETag, use stale-while-revalidate\n8. **Retries**: Implement exponential backoff with jitter\n","isInternal":false,"tokens":798,"sizeBytes":3335},{"name":"logging-observability.md","path":"src/resources/skills/code-optimizer/references/logging-observability.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/references/logging-observability.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Logging & Observability Performance\n\n## Grep/Glob Patterns to Detect\n\n### Excessive Logging\n```\nconsole\\.log\\(                     (console.log in production code)\nconsole\\.debug\\(                   (console.debug in production)\nprint\\(.*debug                     (Python print debugging)\nlogger\\.debug\\(.*inside.*loop      (debug logging in hot loop)\nlog\\.\\w+\\(.*inside.*for            (any logging in tight loop)\nconsole\\.log\\(JSON\\.stringify\\(    (serializing objects just to log)\n```\n\n### Expensive String Formatting in Logs\n```\n# String interpolation/formatting when log level is disabled\nlogger\\.debug\\(f\"                  (Python f-string even when debug disabled)\nlogger\\.debug\\(.*\\.format\\(        (Python .format() even when debug disabled)\nlogger\\.debug\\(`                   (JS template literal even when debug disabled)\nlogger\\.debug\\(.*\\+.*\\+            (string concat for debug log)\nJSON\\.stringify\\(.*log             (JSON stringify for logging)\n```\n\n### Missing Structured Logging\n```\nconsole\\.log\\([\"'].*:.*[\"']        (unstructured string logging)\nprint\\(.*[\"'].*:.*[\"']             (unstructured print logging)\nlogger\\.\\w+\\([\"'].*[\"'] %         (format string logging vs structured)\n```\n\n### Synchronous Logging\n```\nfs\\.writeFileSync.*log             (sync file write for logging)\nfs\\.appendFileSync.*log            (sync file append for logging)\nopen\\(.*log.*\\)\\.write\\(          (Python: sync log file write)\n```\n\n### Missing Request/Trace IDs\n```\n# API handlers without correlation IDs\napp\\.(get|post)\\(.*req.*res       (check if request ID is propagated)\n@app\\.route\\(                      (check if request ID middleware exists)\n```\n\n### Metrics Collection Overhead\n```\n# Metrics in hot paths\n\\.observe\\(.*inside.*loop         (Prometheus observe in loop)\n\\.increment\\(.*inside.*loop       (counter increment in loop)\nstatsd\\..*inside.*loop            (StatsD in loop)\n\\.timing\\(.*inside.*loop          (timing metric in loop)\nDate\\.now\\(\\).*Date\\.now\\(\\)      (manual timing - use proper instrumentation)\nperformance\\.now\\(\\).*performance (manual performance timing)\n```\n\n## Improvement Strategies\n\n1. **Console.log**: Remove from production, use proper logger with levels\n2. **Log formatting**: Use lazy evaluation - logger.debug(\"msg %s\", expensive_value) vs f-strings\n3. **Structured logging**: Use JSON structured logs for machine parsing\n4. **Async logging**: Buffer and flush logs asynchronously, don't block request handling\n5. **Request IDs**: Add correlation ID middleware, propagate through all service calls\n6. **Metrics**: Pre-aggregate metrics, use histograms instead of per-request timers in hot loops\n","isInternal":false,"tokens":609,"sizeBytes":2644},{"name":"memory-resources.md","path":"src/resources/skills/code-optimizer/references/memory-resources.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/references/memory-resources.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Memory & Resource Management\n\n## Grep/Glob Patterns to Detect\n\n### Memory Leaks\n```\n# Event listeners never removed\naddEventListener.*without.*removeEventListener\n\\.on\\(.*without.*\\.off\\(\n\\.subscribe\\(.*without.*unsubscribe\n# Timers never cleared\nsetInterval\\(.*without.*clearInterval\nsetTimeout\\(.*without.*clearTimeout\n# Global/module-level caches without eviction\nglobal.*\\[\\]        (unbounded global arrays)\nglobal.*\\{\\}        (unbounded global dicts/objects)\nmodule\\.exports.*cache.*=.*\\{\\}\n_cache\\s*=\\s*\\{\\}   (module-level cache without LRU/TTL)\n# Closures retaining references\nclosure.*large.*object\n# React-specific\nuseEffect.*without.*cleanup\nuseRef.*large.*object\n```\n\n### Unclosed Resources\n```\nopen\\(.*without.*close\nopen\\(.*without.*with\\s   (Python: not using context manager)\nnew FileReader\\(.*without.*close\ncreateReadStream\\(.*without.*destroy\ncreateWriteStream\\(.*without.*end\nfs\\.open\\(.*without.*fs\\.close\nnew Socket\\(.*without.*\\.close\nnew WebSocket\\(.*without.*\\.close\nacquire\\(.*without.*release\n```\n\n### Large Allocations\n```\nnew Array\\(\\d{5,}       (arrays > 10k elements)\nBuffer\\.alloc\\(\\d{6,}   (buffers > 1MB)\n\\.fill\\(.*\\d{6,}        (filling large arrays)\n\\.repeat\\(\\d{4,}         (string repeat large count)\nJSON\\.parse\\(.*large     (parsing large JSON in memory)\n\\.readFileSync\\(          (synchronous large file reads)\n\\.readFile\\(.*without.*stream  (reading whole file vs streaming)\n```\n\n### String Concatenation in Loops\n```\n\\+=.*string.*for\n\\+=.*\\\".*loop\nstr\\s*\\+=              (Python string concat in loop)\n\\.join\\(\\[              (check if used correctly)\n```\n\n## Improvement Strategies\n\n1. **Event listeners**: Always pair add/remove, use AbortController for bulk cleanup\n2. **Timers**: Clear intervals in cleanup/unmount, use refs for timer IDs\n3. **Caches**: Use LRU cache with max size, add TTL, use WeakMap/WeakRef where possible\n4. **File handling**: Use context managers (Python with), try-finally, or using statements\n5. **Streams**: Use streaming for large data instead of loading everything in memory\n6. **String building**: Use StringBuilder/list join pattern instead of concatenation in loops\n7. **Buffers**: Pool and reuse buffers, use streaming transforms\n","isInternal":false,"tokens":575,"sizeBytes":2213},{"name":"rendering-ui.md","path":"src/resources/skills/code-optimizer/references/rendering-ui.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/references/rendering-ui.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Rendering & UI Performance\n\n## Grep/Glob Patterns to Detect\n\n### React Re-render Issues\n```\n# Missing memoization\nconst\\s+\\w+\\s*=\\s*\\(\\s*\\)\\s*=>.*return\\s*\\(    (inline component definitions)\n\\w+\\s*=\\s*\\{.*\\}.*prop=                          (object literal as prop - new ref every render)\n\\w+\\s*=\\s*\\[.*\\].*prop=                          (array literal as prop)\n\\w+\\s*=\\s*\\(\\).*=>.*prop=                        (arrow function as prop - new ref every render)\nstyle=\\{\\{                                        (inline style object)\n# Context causing re-renders\nuseContext\\(                                       (check context value stability)\n<\\w+Provider\\s+value=\\{\\{                         (new object in Provider value)\n<\\w+Provider\\s+value=\\{[^}]*\\}                    (unstable provider value)\n# State management\nuseState\\(.*\\{                                     (object state - check if needs splitting)\nsetState\\(.*\\{\\.\\.\\.state                          (spreading entire state on each update)\n```\n\n### Missing Virtualization\n```\n\\.map\\(.*<\\w+                  (rendering list items - check list size)\n{items\\.map\\(                  (JSX list rendering - check if >50 items)\n\\.map\\(.*return.*<li           (list rendering without virtualization)\n\\.map\\(.*return.*<tr           (table row rendering without virtualization)\n\\.map\\(.*return.*<div          (div list - check count)\nv-for=                         (Vue list rendering)\nngFor                          (Angular list rendering)\n```\n\n### Layout Thrashing\n```\noffsetWidth.*style\\.           (read then write in sequence)\noffsetHeight.*style\\.          (read then write)\ngetBoundingClientRect.*style   (read then write)\nclientWidth.*className         (read then class change)\nscrollTop.*style               (read then write)\n\\.style\\..*\\.style\\.           (multiple style writes - batch with class)\n```\n\n### Large DOM\n```\ndocument\\.createElement.*loop  (creating elements in loop)\ninnerHTML\\s*\\+=                (innerHTML concatenation - causes reparse)\n\\.appendChild\\(.*loop          (appending in loop without fragment)\ndocument\\.querySelector\\(.*loop (DOM query in loop)\n\\$\\(.*\\).*loop                 (jQuery selector in loop)\n```\n\n### Missing Lazy Loading\n```\n<img\\s+(?!.*loading)           (images without loading=\"lazy\")\n<iframe\\s+(?!.*loading)        (iframes without lazy loading)\nimport.*above.*fold            (heavy imports for below-fold content)\n```\n\n### Animation Performance\n```\n# Layout-triggering animations\nanimate.*width                 (animating width triggers layout)\nanimate.*height                (animating height triggers layout)\nanimate.*top                   (animating top triggers layout)\nanimate.*left                  (animating left triggers layout)\nanimate.*margin                (animating margin triggers layout)\ntransition.*width              (transitioning layout properties)\ntransition.*height\n# Should use transform/opacity instead\n@keyframes.*\\{.*(?:width|height|top|left|margin|padding)\n```\n\n### SSR/Hydration Issues\n```\nuseEffect\\(.*\\[\\].*setState   (client-side data fetch causing hydration mismatch)\ntypeof window                  (window checks indicating SSR issues)\ndocument\\.                     (direct document access in components)\nwindow\\.                       (direct window access in components)\n```\n\n## Improvement Strategies\n\n1. **Re-renders**: Use React.memo, useMemo, useCallback for stable references\n2. **Context**: Split contexts by update frequency, memoize provider values\n3. **Virtualization**: Use react-window/react-virtuoso for lists > 50 items\n4. **Layout thrashing**: Batch reads, then batch writes; use requestAnimationFrame\n5. **DOM manipulation**: Use DocumentFragment, batch insertions, avoid innerHTML +=\n6. **Lazy loading**: Add loading=\"lazy\" to images/iframes, use Intersection Observer\n7. **Animations**: Only animate transform and opacity (GPU-composited properties)\n8. **SSR**: Pre-fetch data server-side, avoid hydration mismatches\n","isInternal":false,"tokens":881,"sizeBytes":3983},{"name":"security-performance.md","path":"src/resources/skills/code-optimizer/references/security-performance.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/references/security-performance.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Security-Related Performance Issues\n\n## Grep/Glob Patterns to Detect\n\n### Cryptographic Misuse\n```\nmd5\\(                              (MD5 is fast but broken - use bcrypt/argon2 for passwords)\nsha1\\(                             (SHA1 is weak)\n\\.hashSync\\(.*rounds.*[1-5]\\b     (bcrypt with low rounds)\nDES\\b                              (DES is obsolete)\nMath\\.random\\(\\).*token            (Math.random for security tokens)\nMath\\.random\\(\\).*password         (Math.random for password generation)\nrandom\\.random\\(\\).*secret         (Python: insecure random for secrets)\n```\n\n### Expensive Security Operations in Hot Paths\n```\nbcrypt.*inside.*loop               (hashing in loop - expensive by design)\njwt\\.verify\\(.*inside.*loop        (JWT verification in loop)\nencrypt\\(.*inside.*loop            (encryption in loop)\n\\.hash\\(.*inside.*loop             (hashing in loop)\n```\n\n### Missing Rate Limiting\n```\napp\\.(get|post|put|delete)\\(       (routes without rate limiting)\n@app\\.route\\(                      (Flask routes without rate limiting)\nrouter\\.(get|post|put|delete)\\(    (Express routes without rate limiting)\n```\n\n### SQL Injection Vectors (Also Performance)\n```\nf\"SELECT.*\\{                       (Python f-string SQL)\nf\"INSERT.*\\{                       (Python f-string SQL)\n`SELECT.*\\$\\{                      (JS template literal SQL)\n\"SELECT.*\" \\+ \\w+                  (string concat SQL)\n'SELECT.*' \\+ \\w+                  (string concat SQL)\n\\.raw\\(.*\\+                        (raw query with concatenation)\n\\.execute\\(.*%.*%                  (Python format string SQL)\n```\n\n### ReDoS Vulnerable Patterns\n```\n\\(\\.\\*\\)\\+                         (catastrophic backtracking)\n\\(\\.\\+\\)\\+                         (catastrophic backtracking)\n\\([^)]*\\|[^)]*\\)\\+                (alternation with repetition)\n\\(\\[.*\\]\\+\\)\\+                    (nested quantifiers)\nnew RegExp\\(.*user                 (user input in regex)\nre\\.compile\\(.*user                (Python: user input in regex)\n```\n\n### N+1 Auth Checks\n```\n# Checking permissions inside loops\n\\.can\\(.*inside.*loop             (permission check in loop)\n\\.authorize\\(.*inside.*loop       (authorization in loop)\nisAllowed\\(.*inside.*loop         (permission check in loop)\nhasPermission\\(.*inside.*loop     (permission check in loop)\n```\n\n## Improvement Strategies\n\n1. **Crypto**: Use bcrypt/argon2 for passwords, SHA-256+ for hashing, crypto.randomBytes for tokens\n2. **Hot path crypto**: Cache JWT verification results, batch encrypt/decrypt\n3. **Rate limiting**: Add rate limiters (express-rate-limit, django-ratelimit, etc.)\n4. **SQL injection**: Use parameterized queries/prepared statements (also faster due to query plan caching)\n5. **ReDoS**: Audit regex patterns, use RE2 engine, set regex timeouts\n6. **Auth batching**: Batch permission checks, pre-load permissions per request\n","isInternal":false,"tokens":674,"sizeBytes":2854},{"name":"SKILL.md","path":"src/resources/skills/code-optimizer/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/code-optimizer/SKILL.md","title":"code-optimizer","category":"anthropic-skill","format":"markdown","content":"---\nname: code-optimizer\ndescription: >\n  Deep code optimization audit using parallel specialist agents. Each agent hunts for performance\n  anti-patterns, inefficiencies, and suboptimal code using pattern-based detection (Grep/Glob)\n  WITHOUT reading the full source code first — avoiding anchoring bias on existing implementations.\n  Covers ALL optimization domains: database queries, memory leaks, algorithmic complexity,\n  concurrency, bundle size, dead code, I/O & network, rendering/UI, data structures,\n  error handling, caching, build config, security-performance, logging, and infrastructure.\n  Use when asked to: \"optimize my code\", \"find performance issues\", \"audit code quality\",\n  \"speed up my app\", \"find bottlenecks\", \"code review for performance\", \"find anti-patterns\",\n  \"improve code efficiency\", \"reduce latency\", \"optimize performance\", \"code smell detection\",\n  \"find slow code\", \"optimize this project\", \"performance audit\", \"code optimization\".\n  Also triggers on: \"optimizar codigo\", \"encontrar cuellos de botella\", \"mejorar rendimiento\".\n---\n\n# Code Optimizer\n\nParallel multi-agent code optimization audit. Spawn 13 specialist agents simultaneously, each\nhunting for a different class of performance problem using pattern-based detection.\n\n## Critical Principle: No Code Reading Before Analysis\n\nAgents MUST NOT read source files before searching for patterns. Reading the code first causes\nanchoring bias — the agent accepts the existing implementation as \"reasonable\" and misses\nbetter alternatives. Instead, each agent:\n\n1. Read its assigned reference file from `references/` to load detection patterns\n2. Use Grep/Glob to scan the codebase for anti-patterns\n3. For each finding, ONLY THEN read the surrounding context (5-10 lines) to confirm the issue\n4. Propose the optimal solution based on best practices, NOT based on the existing code\n\n## Workflow\n\n### Step 1: Detect Stack\n\nUse Glob to identify the project's tech stack:\n- `**/package.json` → Node.js/JS/TS (check for React, Next.js, Express, etc.)\n- `**/requirements.txt`, `**/pyproject.toml`, `**/setup.py` → Python\n- `**/go.mod` → Go\n- `**/Cargo.toml` → Rust\n- `**/pom.xml`, `**/build.gradle` → Java\n- `**/Gemfile` → Ruby\n- `**/Dockerfile` → Docker\n- `**/*.sql` → SQL\n- `**/webpack.config.*`, `**/vite.config.*`, `**/tsconfig.json` → Build tools\n\n### Step 2: Spawn 13 Parallel Agents\n\nLaunch ALL agents simultaneously using the Agent tool. Each agent receives:\n- Its domain name and reference file path\n- The detected tech stack (so it can focus on relevant patterns)\n- The project root path\n- Instructions to NOT read code files, only Grep/Glob for patterns\n\n**Agent definitions** (spawn all 13 in a single message):\n\n| # | Agent Name | Reference File | Focus |\n|---|-----------|----------------|-------|\n| 1 | Database & Queries | `references/database-queries.md` | N+1 queries, SELECT *, missing indexes, ORM misuse, connection pooling |\n| 2 | Memory & Resources | `references/memory-resources.md` | Memory leaks, unclosed resources, large allocations, string concat in loops |\n| 3 | Algorithmic Complexity | `references/algorithmic-complexity.md` | O(n^2) patterns, unnecessary iterations, wrong data structures for lookups |\n| 4 | Concurrency & Async | `references/concurrency-async.md` | Sequential awaits, blocking in async, race conditions, unbounded concurrency |\n| 5 | Bundle & Dependencies | `references/bundle-dependencies.md` | Heavy imports, unused deps, duplicate libs, missing lazy loading |\n| 6 | Dead Code & Redundancy | `references/dead-code-redundancy.md` | Unused exports, commented code, dead branches, duplicate logic |\n| 7 | I/O & Network | `references/io-network.md` | Sequential requests, missing batching, no dedup, missing compression |\n| 8 | Rendering & UI | `references/rendering-ui.md` | Re-renders, missing virtualization, layout thrashing, animation perf |\n| 9 | Data Structures | `references/data-structures.md` | Wrong structures, unnecessary copies, inefficient serialization |\n| 10 | Error & Resilience | `references/error-resilience.md` | Missing timeouts, swallowed errors, no retries, no circuit breakers |\n| 11 | Caching & Memoization | `references/caching-memoization.md` | Missing memoization, cache without invalidation, redundant API calls |\n| 12 | Build & Compilation | `references/build-compilation.md` | Dev code in prod, missing optimization flags, slow tests, Docker issues |\n| 13 | Security-Performance | `references/security-performance.md` | Crypto misuse, missing rate limiting, ReDoS, SQL injection vectors |\n\n**Optional agents** (spawn if relevant to detected stack):\n- Logging & Observability (`references/logging-observability.md`) — if logging framework detected\n- Config & Infrastructure (`references/config-infra.md`) — if Docker/deployment config detected\n\n### Agent Prompt Template\n\nEach agent MUST receive this prompt structure:\n\n```\nYou are a {DOMAIN_NAME} optimization specialist. Your job is to find performance\nanti-patterns in the codebase at {PROJECT_ROOT}.\n\nCRITICAL RULES:\n1. DO NOT read source code files before searching. This avoids anchoring bias.\n2. First, read your reference file: {SKILL_DIR}/references/{REFERENCE_FILE}\n3. Use Grep and Glob to search for the patterns described in the reference file.\n4. Only read 5-10 lines of context around each finding to confirm it's a real issue.\n5. Skip patterns that don't match the project's stack: {DETECTED_STACK}\n\nTech stack detected: {DETECTED_STACK}\nProject root: {PROJECT_ROOT}\n\nFor each finding, report:\n- **File**: path:line_number\n- **Pattern**: what anti-pattern was detected\n- **Severity**: CRITICAL / HIGH / MEDIUM / LOW\n- **Current code**: the problematic snippet (keep short)\n- **Why it's slow**: brief explanation of the performance impact\n- **Optimal fix**: the recommended solution (code snippet or approach)\n- **Estimated impact**: qualitative improvement expected (e.g., \"10x faster for large lists\")\n\nIf you find 0 issues in your domain, report \"No issues found\" — this is a valid outcome.\nSort findings by severity (CRITICAL first).\n```\n\n### Step 3: Consolidate Report\n\nAfter all agents complete, consolidate their findings into a single prioritized report:\n\n1. Collect all findings from all agents\n2. Deduplicate (different agents may flag the same code for different reasons)\n3. Sort by severity: CRITICAL > HIGH > MEDIUM > LOW\n4. Group by file (so the user can fix file-by-file)\n5. Present the final report with:\n   - Executive summary: total findings by severity, top 3 most impactful\n   - Detailed findings table grouped by file\n   - Improvement plan: ordered list of fixes from highest to lowest impact\n\n### Report Format\n\n```markdown\n# Code Optimization Audit Report\n\n## Executive Summary\n- **X** critical issues, **Y** high, **Z** medium, **W** low\n- Top 3 highest-impact fixes:\n  1. [brief description] — [estimated impact]\n  2. [brief description] — [estimated impact]\n  3. [brief description] — [estimated impact]\n\n## Findings by File\n\n### `path/to/file.ts`\n\n| # | Severity | Domain | Pattern | Fix | Impact |\n|---|----------|--------|---------|-----|--------|\n| 1 | CRITICAL | Database | N+1 query in loop | Use prefetch_related | 50x fewer queries |\n| 2 | HIGH | Async | Sequential awaits | Use Promise.all | 3x faster |\n\n[... for each file with findings ...]\n\n## Improvement Plan\n\nPriority-ordered steps to implement the fixes:\n\n1. **[CRITICAL] Fix N+1 queries in `api/users.py`**\n   - Current: loop queries user.posts for each user\n   - Fix: add prefetch_related('posts') to queryset\n   - Impact: reduces N+1 to 2 queries\n\n2. **[HIGH] Parallelize API calls in `services/sync.ts`**\n   - Current: 5 sequential await fetch() calls\n   - Fix: Promise.all([fetch1, fetch2, ...])\n   - Impact: ~5x faster sync operation\n\n[... continue for all findings ...]\n```\n","frontmatter":{"name":"code-optimizer","description":"Deep code optimization audit using parallel specialist agents. Each agent hunts for performance anti-patterns, inefficiencies, and suboptimal code using pattern-based detection (Grep/Glob) WITHOUT reading the full source code first — avoiding anchoring bias on existing implementations. Covers ALL optimization domains: database queries, memory leaks, algorithmic complexity, concurrency, bundle size, dead code, I/O & network, rendering/UI, data structures, error handling, caching, build config, security-performance, logging, and infrastructure. Use when asked to: \"optimize my code\", \"find performance issues\", \"audit code quality\", \"speed up my app\", \"find bottlenecks\", \"code review for performance\", \"find anti-patterns\", \"improve code efficiency\", \"reduce latency\", \"optimize performance\", \"code smell detection\", \"find slow code\", \"optimize this project\", \"performance audit\", \"code optimization\". Also triggers on: \"optimizar codigo\", \"encontrar cuellos de botella\", \"mejorar rendimiento\".\n"},"isInternal":false,"tokens":1862,"sizeBytes":7832},{"name":"LCP.md","path":"src/resources/skills/core-web-vitals/references/LCP.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/core-web-vitals/references/LCP.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# LCP optimization reference\n\n## What is LCP?\n\nLargest Contentful Paint (LCP) measures when the largest content element in the viewport becomes visible. This is typically:\n\n- An `<img>` element\n- An `<image>` element inside `<svg>`\n- A `<video>` element with poster image\n- An element with a background image via `url()`\n- A block-level element containing text nodes\n\n## LCP timeline\n\n```\n[  Server Response  ][  Resource Load  ][  Render  ]\n       TTFB              Download         Paint\n       └─────────────────────────────────────┘\n                         LCP Time\n```\n\n## Detailed optimizations\n\n### 1. Server response time (TTFB)\n\nTarget: < 800ms\n\n**Causes:**\n- Slow server/database queries\n- No CDN/edge caching\n- Inefficient backend code\n- Cold starts (serverless)\n\n**Solutions:**\n```javascript\n// Use edge functions for dynamic content\n// Vercel example\nexport const config = { runtime: 'edge' };\n\n// Use stale-while-revalidate caching\n// Cache-Control header\nres.setHeader('Cache-Control', 's-maxage=60, stale-while-revalidate=300');\n```\n\n### 2. Resource load time\n\n**For images:**\n```html\n<!-- Preload LCP image -->\n<link rel=\"preload\" as=\"image\" href=\"/hero.webp\" \n      imagesrcset=\"/hero-400.webp 400w, /hero-800.webp 800w\"\n      imagesizes=\"100vw\"\n      fetchpriority=\"high\">\n\n<!-- Modern format with fallback -->\n<picture>\n  <source srcset=\"/hero.avif\" type=\"image/avif\">\n  <source srcset=\"/hero.webp\" type=\"image/webp\">\n  <img src=\"/hero.jpg\" width=\"1200\" height=\"600\" \n       fetchpriority=\"high\" alt=\"Hero\">\n</picture>\n```\n\n**For text (web fonts):**\n```css\n@font-face {\n  font-family: 'Heading';\n  src: url('/fonts/heading.woff2') format('woff2');\n  font-display: swap; /* Show fallback immediately */\n}\n```\n\n### 3. Render blocking resources\n\n**Critical CSS pattern:**\n```html\n<head>\n  <!-- Inline critical CSS -->\n  <style>\n    /* Only above-fold styles, < 14KB */\n    .hero { /* ... */ }\n    .nav { /* ... */ }\n  </style>\n  \n  <!-- Defer non-critical CSS -->\n  <link rel=\"preload\" href=\"/styles.css\" as=\"style\" \n        onload=\"this.onload=null;this.rel='stylesheet'\">\n</head>\n```\n\n**Defer JavaScript:**\n```html\n<!-- ❌ Blocks parsing -->\n<script src=\"/app.js\"></script>\n\n<!-- ✅ Deferred (runs after HTML parsed) -->\n<script defer src=\"/app.js\"></script>\n\n<!-- ✅ Module (deferred by default) -->\n<script type=\"module\" src=\"/app.mjs\"></script>\n```\n\n### 4. Client-side rendering\n\n**Problem:** Content not in initial HTML.\n\n**Solutions:**\n\n**Server-side rendering (SSR):**\n```javascript\n// Next.js\nexport async function getServerSideProps() {\n  const data = await fetchHeroContent();\n  return { props: { hero: data } };\n}\n```\n\n**Static site generation (SSG):**\n```javascript\n// Next.js\nexport async function getStaticProps() {\n  const data = await fetchHeroContent();\n  return { props: { hero: data }, revalidate: 3600 };\n}\n```\n\n**Streaming SSR:**\n```jsx\n// React 18+\nimport { Suspense } from 'react';\n\nfunction Page() {\n  return (\n    <Suspense fallback={<HeroSkeleton />}>\n      <Hero />\n    </Suspense>\n  );\n}\n```\n\n## Framework-specific tips\n\n### Next.js\n```jsx\nimport Image from 'next/image';\n\n// LCP image with priority\n<Image \n  src=\"/hero.jpg\"\n  priority\n  fill\n  sizes=\"100vw\"\n  alt=\"Hero\"\n/>\n```\n\n### Nuxt\n```vue\n<NuxtImg\n  src=\"/hero.jpg\"\n  preload\n  loading=\"eager\"\n  sizes=\"100vw\"\n/>\n```\n\n### Astro\n```astro\n---\nimport { Image } from 'astro:assets';\nimport hero from '../assets/hero.jpg';\n---\n<Image \n  src={hero} \n  loading=\"eager\" \n  decoding=\"sync\"\n  alt=\"Hero\" \n/>\n```\n\n## Debugging LCP\n\n```javascript\n// Identify LCP element\nnew PerformanceObserver((entryList) => {\n  const entries = entryList.getEntries();\n  const lastEntry = entries[entries.length - 1];\n  \n  console.log('LCP:', {\n    element: lastEntry.element,\n    time: lastEntry.startTime,\n    size: lastEntry.size,\n    url: lastEntry.url,\n    renderTime: lastEntry.renderTime,\n    loadTime: lastEntry.loadTime\n  });\n}).observe({ type: 'largest-contentful-paint', buffered: true });\n```\n\n## Common issues\n\n| Issue | Impact | Fix |\n|-------|--------|-----|\n| No preload for LCP image | +500-1000ms | Add `<link rel=\"preload\">` |\n| Large unoptimized image | +300-800ms | Compress, use WebP/AVIF |\n| Render-blocking CSS | +200-500ms | Inline critical CSS |\n| Slow TTFB | +300-2000ms | CDN, edge caching |\n| Client-rendered content | +500-2000ms | SSR/SSG |\n","isInternal":false,"tokens":1196,"sizeBytes":4431},{"name":"SKILL.md","path":"src/resources/skills/core-web-vitals/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/core-web-vitals/SKILL.md","title":"core-web-vitals","category":"anthropic-skill","format":"markdown","content":"---\nname: core-web-vitals\ndescription: Optimize Core Web Vitals (LCP, INP, CLS) for better page experience and search ranking. Use when asked to \"improve Core Web Vitals\", \"fix LCP\", \"reduce CLS\", \"optimize INP\", \"page experience optimization\", or \"fix layout shifts\".\nlicense: MIT\nmetadata:\n  author: web-quality-skills\n  version: \"1.0\"\n---\n\n# Core Web Vitals optimization\n\nTargeted optimization for the three Core Web Vitals metrics that affect Google Search ranking and user experience.\n\n## The three metrics\n\n| Metric | Measures | Good | Needs work | Poor |\n|--------|----------|------|------------|------|\n| **LCP** | Loading | ≤ 2.5s | 2.5s – 4s | > 4s |\n| **INP** | Interactivity | ≤ 200ms | 200ms – 500ms | > 500ms |\n| **CLS** | Visual Stability | ≤ 0.1 | 0.1 – 0.25 | > 0.25 |\n\nGoogle measures at the **75th percentile** — 75% of page visits must meet \"Good\" thresholds.\n\n---\n\n## LCP: Largest Contentful Paint\n\nLCP measures when the largest visible content element renders. Usually this is:\n- Hero image or video\n- Large text block\n- Background image\n- `<svg>` element\n\n### Common LCP issues\n\n**1. Slow server response (TTFB > 800ms)**\n```\nFix: CDN, caching, optimized backend, edge rendering\n```\n\n**2. Render-blocking resources**\n```html\n<!-- ❌ Blocks rendering -->\n<link rel=\"stylesheet\" href=\"/all-styles.css\">\n\n<!-- ✅ Critical CSS inlined, rest deferred -->\n<style>/* Critical above-fold CSS */</style>\n<link rel=\"preload\" href=\"/styles.css\" as=\"style\" \n      onload=\"this.onload=null;this.rel='stylesheet'\">\n```\n\n**3. Slow resource load times**\n```html\n<!-- ❌ No hints, discovered late -->\n<img src=\"/hero.jpg\" alt=\"Hero\">\n\n<!-- ✅ Preloaded with high priority -->\n<link rel=\"preload\" href=\"/hero.webp\" as=\"image\" fetchpriority=\"high\">\n<img src=\"/hero.webp\" alt=\"Hero\" fetchpriority=\"high\">\n```\n\n**4. Client-side rendering delays**\n```javascript\n// ❌ Content loads after JavaScript\nuseEffect(() => {\n  fetch('/api/hero-text').then(r => r.json()).then(setHeroText);\n}, []);\n\n// ✅ Server-side or static rendering\n// Use SSR, SSG, or streaming to send HTML with content\nexport async function getServerSideProps() {\n  const heroText = await fetchHeroText();\n  return { props: { heroText } };\n}\n```\n\n### LCP optimization checklist\n\n```markdown\n- [ ] TTFB < 800ms (use CDN, edge caching)\n- [ ] LCP image preloaded with fetchpriority=\"high\"\n- [ ] LCP image optimized (WebP/AVIF, correct size)\n- [ ] Critical CSS inlined (< 14KB)\n- [ ] No render-blocking JavaScript in <head>\n- [ ] Fonts don't block text rendering (font-display: swap)\n- [ ] LCP element in initial HTML (not JS-rendered)\n```\n\n### LCP element identification\n```javascript\n// Find your LCP element\nnew PerformanceObserver((list) => {\n  const entries = list.getEntries();\n  const lastEntry = entries[entries.length - 1];\n  console.log('LCP element:', lastEntry.element);\n  console.log('LCP time:', lastEntry.startTime);\n}).observe({ type: 'largest-contentful-paint', buffered: true });\n```\n\n---\n\n## INP: Interaction to Next Paint\n\nINP measures responsiveness across ALL interactions (clicks, taps, key presses) during a page visit. It reports the worst interaction (at 98th percentile for high-traffic pages).\n\n### INP breakdown\n\nTotal INP = **Input Delay** + **Processing Time** + **Presentation Delay**\n\n| Phase | Target | Optimization |\n|-------|--------|--------------|\n| Input Delay | < 50ms | Reduce main thread blocking |\n| Processing | < 100ms | Optimize event handlers |\n| Presentation | < 50ms | Minimize rendering work |\n\n### Common INP issues\n\n**1. Long tasks blocking main thread**\n```javascript\n// ❌ Long synchronous task\nfunction processLargeArray(items) {\n  items.forEach(item => expensiveOperation(item));\n}\n\n// ✅ Break into chunks with yielding\nasync function processLargeArray(items) {\n  const CHUNK_SIZE = 100;\n  for (let i = 0; i < items.length; i += CHUNK_SIZE) {\n    const chunk = items.slice(i, i + CHUNK_SIZE);\n    chunk.forEach(item => expensiveOperation(item));\n    \n    // Yield to main thread\n    await new Promise(r => setTimeout(r, 0));\n    // Or use scheduler.yield() when available\n  }\n}\n```\n\n**2. Heavy event handlers**\n```javascript\n// ❌ All work in handler\nbutton.addEventListener('click', () => {\n  // Heavy computation\n  const result = calculateComplexThing();\n  // DOM updates\n  updateUI(result);\n  // Analytics\n  trackEvent('click');\n});\n\n// ✅ Prioritize visual feedback\nbutton.addEventListener('click', () => {\n  // Immediate visual feedback\n  button.classList.add('loading');\n  \n  // Defer non-critical work\n  requestAnimationFrame(() => {\n    const result = calculateComplexThing();\n    updateUI(result);\n  });\n  \n  // Use requestIdleCallback for analytics\n  requestIdleCallback(() => trackEvent('click'));\n});\n```\n\n**3. Third-party scripts**\n```javascript\n// ❌ Eagerly loaded, blocks interactions\n<script src=\"https://heavy-widget.com/widget.js\"></script>\n\n// ✅ Lazy loaded on interaction or visibility\nconst loadWidget = () => {\n  import('https://heavy-widget.com/widget.js')\n    .then(widget => widget.init());\n};\nbutton.addEventListener('click', loadWidget, { once: true });\n```\n\n**4. Excessive re-renders (React/Vue)**\n```javascript\n// ❌ Re-renders entire tree\nfunction App() {\n  const [count, setCount] = useState(0);\n  return (\n    <div>\n      <Counter count={count} />\n      <ExpensiveComponent /> {/* Re-renders on every count change */}\n    </div>\n  );\n}\n\n// ✅ Memoized expensive components\nconst MemoizedExpensive = React.memo(ExpensiveComponent);\n\nfunction App() {\n  const [count, setCount] = useState(0);\n  return (\n    <div>\n      <Counter count={count} />\n      <MemoizedExpensive />\n    </div>\n  );\n}\n```\n\n### INP optimization checklist\n\n```markdown\n- [ ] No tasks > 50ms on main thread\n- [ ] Event handlers complete quickly (< 100ms)\n- [ ] Visual feedback provided immediately\n- [ ] Heavy work deferred with requestIdleCallback\n- [ ] Third-party scripts don't block interactions\n- [ ] Debounced input handlers where appropriate\n- [ ] Web Workers for CPU-intensive operations\n```\n\n### INP debugging\n```javascript\n// Identify slow interactions\nnew PerformanceObserver((list) => {\n  for (const entry of list.getEntries()) {\n    if (entry.duration > 200) {\n      console.warn('Slow interaction:', {\n        type: entry.name,\n        duration: entry.duration,\n        processingStart: entry.processingStart,\n        processingEnd: entry.processingEnd,\n        target: entry.target\n      });\n    }\n  }\n}).observe({ type: 'event', buffered: true, durationThreshold: 16 });\n```\n\n---\n\n## CLS: Cumulative Layout Shift\n\nCLS measures unexpected layout shifts. A shift occurs when a visible element changes position between frames without user interaction.\n\n**CLS Formula:** `impact fraction × distance fraction`\n\n### Common CLS causes\n\n**1. Images without dimensions**\n```html\n<!-- ❌ Causes layout shift when loaded -->\n<img src=\"photo.jpg\" alt=\"Photo\">\n\n<!-- ✅ Space reserved -->\n<img src=\"photo.jpg\" alt=\"Photo\" width=\"800\" height=\"600\">\n\n<!-- ✅ Or use aspect-ratio -->\n<img src=\"photo.jpg\" alt=\"Photo\" style=\"aspect-ratio: 4/3; width: 100%;\">\n```\n\n**2. Ads, embeds, and iframes**\n```html\n<!-- ❌ Unknown size until loaded -->\n<iframe src=\"https://ad-network.com/ad\"></iframe>\n\n<!-- ✅ Reserve space with min-height -->\n<div style=\"min-height: 250px;\">\n  <iframe src=\"https://ad-network.com/ad\" height=\"250\"></iframe>\n</div>\n\n<!-- ✅ Or use aspect-ratio container -->\n<div style=\"aspect-ratio: 16/9;\">\n  <iframe src=\"https://youtube.com/embed/...\" \n          style=\"width: 100%; height: 100%;\"></iframe>\n</div>\n```\n\n**3. Dynamically injected content**\n```javascript\n// ❌ Inserts content above viewport\nnotifications.prepend(newNotification);\n\n// ✅ Insert below viewport or use transform\nconst insertBelow = viewport.bottom < newNotification.top;\nif (insertBelow) {\n  notifications.prepend(newNotification);\n} else {\n  // Animate in without shifting\n  newNotification.style.transform = 'translateY(-100%)';\n  notifications.prepend(newNotification);\n  requestAnimationFrame(() => {\n    newNotification.style.transform = '';\n  });\n}\n```\n\n**4. Web fonts causing FOUT**\n```css\n/* ❌ Font swap shifts text */\n@font-face {\n  font-family: 'Custom';\n  src: url('custom.woff2') format('woff2');\n}\n\n/* ✅ Optional font (no shift if slow) */\n@font-face {\n  font-family: 'Custom';\n  src: url('custom.woff2') format('woff2');\n  font-display: optional;\n}\n\n/* ✅ Or match fallback metrics */\n@font-face {\n  font-family: 'Custom';\n  src: url('custom.woff2') format('woff2');\n  font-display: swap;\n  size-adjust: 105%; /* Match fallback size */\n  ascent-override: 95%;\n  descent-override: 20%;\n}\n```\n\n**5. Animations triggering layout**\n```css\n/* ❌ Animates layout properties */\n.animate {\n  transition: height 0.3s, width 0.3s;\n}\n\n/* ✅ Use transform instead */\n.animate {\n  transition: transform 0.3s;\n}\n.animate.expanded {\n  transform: scale(1.2);\n}\n```\n\n### CLS optimization checklist\n\n```markdown\n- [ ] All images have width/height or aspect-ratio\n- [ ] All videos/embeds have reserved space\n- [ ] Ads have min-height containers\n- [ ] Fonts use font-display: optional or matched metrics\n- [ ] Dynamic content inserted below viewport\n- [ ] Animations use transform/opacity only\n- [ ] No content injected above existing content\n```\n\n### CLS debugging\n```javascript\n// Track layout shifts\nnew PerformanceObserver((list) => {\n  for (const entry of list.getEntries()) {\n    if (!entry.hadRecentInput) {\n      console.log('Layout shift:', entry.value);\n      entry.sources?.forEach(source => {\n        console.log('  Shifted element:', source.node);\n        console.log('  Previous rect:', source.previousRect);\n        console.log('  Current rect:', source.currentRect);\n      });\n    }\n  }\n}).observe({ type: 'layout-shift', buffered: true });\n```\n\n---\n\n## Measurement tools\n\n### Lab testing\n- **Chrome DevTools** → Performance panel, Lighthouse\n- **WebPageTest** → Detailed waterfall, filmstrip\n- **Lighthouse CLI** → `npx lighthouse <url>`\n\n### Field data (real users)\n- **Chrome User Experience Report (CrUX)** → BigQuery or API\n- **Search Console** → Core Web Vitals report\n- **web-vitals library** → Send to your analytics\n\n```javascript\nimport {onLCP, onINP, onCLS} from 'web-vitals';\n\nfunction sendToAnalytics({name, value, rating}) {\n  gtag('event', name, {\n    event_category: 'Web Vitals',\n    value: Math.round(name === 'CLS' ? value * 1000 : value),\n    event_label: rating\n  });\n}\n\nonLCP(sendToAnalytics);\nonINP(sendToAnalytics);\nonCLS(sendToAnalytics);\n```\n\n---\n\n## Framework quick fixes\n\n### Next.js\n```jsx\n// LCP: Use next/image with priority\nimport Image from 'next/image';\n<Image src=\"/hero.jpg\" priority fill alt=\"Hero\" />\n\n// INP: Use dynamic imports\nconst HeavyComponent = dynamic(() => import('./Heavy'), { ssr: false });\n\n// CLS: Image component handles dimensions automatically\n```\n\n### React\n```jsx\n// LCP: Preload in head\n<link rel=\"preload\" href=\"/hero.jpg\" as=\"image\" fetchpriority=\"high\" />\n\n// INP: Memoize and useTransition\nconst [isPending, startTransition] = useTransition();\nstartTransition(() => setExpensiveState(newValue));\n\n// CLS: Always specify dimensions in img tags\n```\n\n### Vue/Nuxt\n```vue\n<!-- LCP: Use nuxt/image with preload -->\n<NuxtImg src=\"/hero.jpg\" preload loading=\"eager\" />\n\n<!-- INP: Use async components -->\n<component :is=\"() => import('./Heavy.vue')\" />\n\n<!-- CLS: Use aspect-ratio CSS -->\n<img :style=\"{ aspectRatio: '16/9' }\" />\n```\n\n## References\n\n- [web.dev LCP](https://web.dev/articles/lcp)\n- [web.dev INP](https://web.dev/articles/inp)\n- [web.dev CLS](https://web.dev/articles/cls)\n- [Code Optimizer skill](../code-optimizer/SKILL.md)\n","frontmatter":{"name":"core-web-vitals","description":"Optimize Core Web Vitals (LCP, INP, CLS) for better page experience and search ranking. Use when asked to \"improve Core Web Vitals\", \"fix LCP\", \"reduce CLS\", \"optimize INP\", \"page experience optimization\", or \"fix layout shifts\".","license":"MIT","metadata":{"author":"web-quality-skills","version":"1.0"}},"isInternal":false,"tokens":2977,"sizeBytes":11675},{"name":"compaction-session-control.md","path":"src/resources/skills/create-gsd-extension/references/compaction-session-control.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/compaction-session-control.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<overview>\nCustom compaction hooks, triggering compaction, and session control methods available only in command handlers.\n</overview>\n\n<custom_compaction>\nOverride default compaction behavior:\n\n```typescript\npi.on(\"session_before_compact\", async (event, ctx) => {\n  const { preparation, branchEntries, customInstructions, signal } = event;\n\n  // Option 1: Cancel\n  return { cancel: true };\n\n  // Option 2: Custom summary\n  return {\n    compaction: {\n      summary: \"Custom summary of conversation so far...\",\n      firstKeptEntryId: preparation.firstKeptEntryId,\n      tokensBefore: preparation.tokensBefore,\n    }\n  };\n});\n```\n</custom_compaction>\n\n<trigger_compaction>\nTrigger compaction programmatically from any handler:\n\n```typescript\nctx.compact({\n  customInstructions: \"Focus on the authentication changes\",\n  onComplete: (result) => ctx.ui.notify(\"Compacted!\", \"info\"),\n  onError: (error) => ctx.ui.notify(`Failed: ${error.message}`, \"error\"),\n});\n```\n</trigger_compaction>\n\n<session_control>\n**Only available in command handlers** (deadlocks in event handlers):\n\n```typescript\npi.registerCommand(\"handoff\", {\n  handler: async (args, ctx) => {\n    await ctx.waitForIdle();\n\n    // Create new session with initial context\n    const result = await ctx.newSession({\n      parentSession: ctx.sessionManager.getSessionFile(),\n      setup: async (sm) => {\n        sm.appendMessage({\n          role: \"user\",\n          content: [{ type: \"text\", text: `Context: ${args}` }],\n          timestamp: Date.now(),\n        });\n      },\n    });\n\n    if (result.cancelled) { /* extension cancelled via session_before_switch */ }\n  },\n});\n```\n\n| Method | Purpose |\n|--------|---------|\n| `ctx.waitForIdle()` | Wait for agent to finish streaming |\n| `ctx.newSession(options?)` | Create a new session |\n| `ctx.fork(entryId)` | Fork from a specific entry |\n| `ctx.navigateTree(targetId, options?)` | Navigate session tree (with optional summary) |\n| `ctx.reload()` | Hot-reload everything (treat as terminal — code after runs pre-reload version) |\n\n`navigateTree` options:\n- `summarize: boolean` — generate summary of abandoned branch\n- `customInstructions: string` — instructions for summarizer\n- `replaceInstructions: boolean` — replace default prompt entirely\n- `label: string` — label to attach to branch summary\n</session_control>\n","isInternal":false,"tokens":535,"sizeBytes":2333},{"name":"custom-commands.md","path":"src/resources/skills/create-gsd-extension/references/custom-commands.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/custom-commands.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<overview>\nCustom slash commands — registration, argument completions, subcommand patterns, and the extended command context.\n</overview>\n\n<basic_registration>\n```typescript\npi.registerCommand(\"deploy\", {\n  description: \"Deploy to an environment\",\n  handler: async (args, ctx) => {\n    // args = everything after \"/deploy \"\n    // ctx = ExtensionCommandContext (has session control methods)\n    ctx.ui.notify(`Deploying to ${args || \"production\"}`, \"info\");\n  },\n});\n```\n</basic_registration>\n\n<argument_completions>\nAdd tab-completion for command arguments:\n\n```typescript\nimport type { AutocompleteItem } from \"@gsd/pi-tui\";\n\npi.registerCommand(\"deploy\", {\n  description: \"Deploy to an environment\",\n  getArgumentCompletions: (prefix: string): AutocompleteItem[] | null => {\n    const envs = [\"dev\", \"staging\", \"prod\"];\n    const items = envs.map(e => ({ value: e, label: e }));\n    const filtered = items.filter(i => i.value.startsWith(prefix));\n    return filtered.length > 0 ? filtered : null;\n  },\n  handler: async (args, ctx) => {\n    ctx.ui.notify(`Deploying to ${args}`, \"info\");\n  },\n});\n```\n</argument_completions>\n\n<subcommand_pattern>\nFake nested commands via first-argument parsing. Used by `/wt new|ls|switch|merge|rm`.\n\n```typescript\npi.registerCommand(\"foo\", {\n  description: \"Manage foo items: /foo new|list|delete [name]\",\n\n  getArgumentCompletions: (prefix: string) => {\n    const parts = prefix.trim().split(/\\s+/);\n\n    // First arg: subcommand\n    if (parts.length <= 1) {\n      return [\"new\", \"list\", \"delete\"]\n        .filter(cmd => cmd.startsWith(parts[0] ?? \"\"))\n        .map(cmd => ({ value: cmd, label: cmd }));\n    }\n\n    // Second arg: depends on subcommand\n    if (parts[0] === \"delete\") {\n      const items = getItemsSomehow();\n      return items\n        .filter(name => name.startsWith(parts[1] ?? \"\"))\n        .map(name => ({ value: `delete ${name}`, label: name }));\n    }\n\n    return [];\n  },\n\n  handler: async (args, ctx) => {\n    const parts = args.trim().split(/\\s+/);\n    const sub = parts[0];\n\n    switch (sub) {\n      case \"new\": /* ... */ return;\n      case \"list\": /* ... */ return;\n      case \"delete\": /* handle parts[1] */ return;\n      default:\n        ctx.ui.notify(\"Usage: /foo <new|list|delete> [name]\", \"info\");\n    }\n  },\n});\n```\n\n**Gotcha:** `\"\".trim().split(/\\s+/)` produces `['']`, not `[]`. That's why `parts.length <= 1` handles both empty and partial first arg.\n</subcommand_pattern>\n\n<command_context>\nCommand handlers get `ExtensionCommandContext` which extends `ExtensionContext` with session control methods:\n\n| Method | Purpose |\n|--------|---------|\n| `ctx.waitForIdle()` | Wait for agent to finish streaming |\n| `ctx.newSession(options?)` | Create a new session |\n| `ctx.fork(entryId)` | Fork from an entry |\n| `ctx.navigateTree(targetId, options?)` | Navigate session tree |\n| `ctx.reload()` | Hot-reload everything |\n\n**⚠️ These methods are ONLY available in command handlers.** Calling them from event handlers causes deadlocks.\n\n```typescript\npi.registerCommand(\"handoff\", {\n  handler: async (args, ctx) => {\n    await ctx.waitForIdle();\n    await ctx.newSession({\n      setup: async (sm) => {\n        sm.appendMessage({\n          role: \"user\",\n          content: [{ type: \"text\", text: `Context: ${args}` }],\n          timestamp: Date.now(),\n        });\n      },\n    });\n  },\n});\n```\n</command_context>\n\n<reload_pattern>\nExpose reload as both a command and a tool the LLM can call:\n\n```typescript\npi.registerCommand(\"reload-runtime\", {\n  description: \"Reload extensions, skills, prompts, and themes\",\n  handler: async (_args, ctx) => {\n    await ctx.reload();\n    return;  // Treat reload as terminal\n  },\n});\n\npi.registerTool({\n  name: \"reload_runtime\",\n  label: \"Reload Runtime\",\n  description: \"Reload extensions, skills, prompts, and themes\",\n  parameters: Type.Object({}),\n  async execute() {\n    pi.sendUserMessage(\"/reload-runtime\", { deliverAs: \"followUp\" });\n    return { content: [{ type: \"text\", text: \"Queued /reload-runtime as follow-up.\" }] };\n  },\n});\n```\n</reload_pattern>\n","isInternal":false,"tokens":1022,"sizeBytes":4067},{"name":"custom-rendering.md","path":"src/resources/skills/create-gsd-extension/references/custom-rendering.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/custom-rendering.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<overview>\nCustom rendering for tools and messages — control how they appear in the TUI.\n</overview>\n\n<tool_rendering>\nTools can provide `renderCall` (how the call looks) and `renderResult` (how the result looks):\n\n```typescript\nimport { Text } from \"@gsd/pi-tui\";\nimport { keyHint } from \"@gsd/pi-coding-agent\";\n\npi.registerTool({\n  name: \"my_tool\",\n  // ...\n\n  renderCall(args, theme) {\n    let text = theme.fg(\"toolTitle\", theme.bold(\"my_tool \"));\n    text += theme.fg(\"muted\", args.action);\n    if (args.text) text += \" \" + theme.fg(\"dim\", `\"${args.text}\"`);\n    return new Text(text, 0, 0);  // 0,0 padding — Box handles it\n  },\n\n  renderResult(result, { expanded, isPartial }, theme) {\n    // isPartial = true during streaming (onUpdate was called)\n    if (isPartial) {\n      return new Text(theme.fg(\"warning\", \"Processing...\"), 0, 0);\n    }\n\n    // expanded = user toggled expand (Ctrl+O)\n    if (result.details?.error) {\n      return new Text(theme.fg(\"error\", `Error: ${result.details.error}`), 0, 0);\n    }\n\n    let text = theme.fg(\"success\", \"✓ Done\");\n    if (!expanded) {\n      text += ` (${keyHint(\"expandTools\", \"to expand\")})`;\n    }\n    if (expanded && result.details?.items) {\n      for (const item of result.details.items) {\n        text += \"\\n  \" + theme.fg(\"dim\", item);\n      }\n    }\n    return new Text(text, 0, 0);\n  },\n});\n```\n\nIf you omit `renderCall`/`renderResult`, the built-in renderer is used. Useful for tool overrides where you just wrap logic without reimplementing UI.\n\n**Fallback:** If render methods throw, `renderCall` shows tool name, `renderResult` shows raw `content` text.\n</tool_rendering>\n\n<key_hints>\nKey hint helpers for showing keybinding info in render output:\n\n```typescript\nimport { keyHint, appKeyHint, editorKey, rawKeyHint } from \"@gsd/pi-coding-agent\";\n\n// Editor action hint (respects user keybinding config)\nkeyHint(\"expandTools\", \"to expand\")    // e.g., \"Ctrl+O to expand\"\nkeyHint(\"selectConfirm\", \"to select\")\n\n// Raw key hint (always shows literal key)\nrawKeyHint(\"Ctrl+O\", \"to expand\")\n```\n</key_hints>\n\n<message_rendering>\nRegister a renderer for custom message types:\n\n```typescript\nimport { Text } from \"@gsd/pi-tui\";\n\npi.registerMessageRenderer(\"my-extension\", (message, options, theme) => {\n  const { expanded } = options;\n  let text = theme.fg(\"accent\", `[${message.customType}] `) + message.content;\n  if (expanded && message.details) {\n    text += \"\\n\" + theme.fg(\"dim\", JSON.stringify(message.details, null, 2));\n  }\n  return new Text(text, 0, 0);\n});\n\n// Send messages that use this renderer:\npi.sendMessage({\n  customType: \"my-extension\",  // Matches renderer name\n  content: \"Status update\",\n  display: true,\n  details: { foo: \"bar\" },\n});\n```\n</message_rendering>\n\n<syntax_highlighting>\n```typescript\nimport { highlightCode, getLanguageFromPath } from \"@gsd/pi-coding-agent\";\n\nconst lang = getLanguageFromPath(\"/path/to/file.rs\");  // \"rust\"\nconst highlighted = highlightCode(code, lang, theme);\n```\n</syntax_highlighting>\n\n<best_practices>\n- Return `Text` with padding `(0, 0)` — the wrapping `Box` handles padding\n- Support `expanded` for detail on demand\n- Handle `isPartial` for streaming progress\n- Keep collapsed view compact\n- Use `\\n` for multi-line content within a single `Text`\n</best_practices>\n","isInternal":false,"tokens":882,"sizeBytes":3290},{"name":"custom-tools.md","path":"src/resources/skills/create-gsd-extension/references/custom-tools.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/custom-tools.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<overview>\nComplete custom tools reference — registration, parameters, execution, output truncation, overrides, rendering, and dynamic registration.\n</overview>\n\n<registration>\n```typescript\nimport { Type } from \"@sinclair/typebox\";\nimport { StringEnum } from \"@gsd/pi-ai\";\n\npi.registerTool({\n  name: \"my_tool\",                    // Unique identifier (snake_case)\n  label: \"My Tool\",                   // Display name in TUI\n  description: \"What this does\",      // Full description shown to LLM\n\n  // Optional: one-liner for system prompt \"Available tools\" section\n  promptSnippet: \"Manage project todo items\",\n\n  // Optional: bullets added to system prompt \"Guidelines\" when tool is active\n  promptGuidelines: [\n    \"Use my_tool for task management instead of file edits.\"\n  ],\n\n  // Parameter schema (MUST use TypeBox)\n  parameters: Type.Object({\n    action: StringEnum([\"list\", \"add\", \"remove\"] as const),\n    text: Type.Optional(Type.String({ description: \"Item text\" })),\n    id: Type.Optional(Type.Number({ description: \"Item ID\" })),\n  }),\n\n  async execute(toolCallId, params, signal, onUpdate, ctx) {\n    // 1. Check cancellation\n    if (signal?.aborted) {\n      return { content: [{ type: \"text\", text: \"Cancelled\" }] };\n    }\n\n    // 2. Stream progress (optional)\n    onUpdate?.({\n      content: [{ type: \"text\", text: \"Working...\" }],\n      details: { progress: 50 },\n    });\n\n    // 3. Do the work\n    const result = await doWork(params);\n\n    // 4. Return result\n    return {\n      content: [{ type: \"text\", text: \"Result text for LLM\" }],  // Sent to LLM context\n      details: { data: result },                                   // For rendering & state\n    };\n  },\n\n  // Optional: custom TUI rendering\n  renderCall(args, theme) { ... },\n  renderResult(result, { expanded, isPartial }, theme) { ... },\n});\n```\n</registration>\n\n<critical_stringenum>\n**⚠️ MUST use `StringEnum` for string enum parameters:**\n\n```typescript\nimport { StringEnum } from \"@gsd/pi-ai\";\n\n// ✅ Correct — works with all providers including Google\naction: StringEnum([\"list\", \"add\", \"remove\"] as const)\n\n// ❌ BROKEN with Google's API\naction: Type.Union([Type.Literal(\"list\"), Type.Literal(\"add\")])\n```\n</critical_stringenum>\n\n<output_truncation>\nTools MUST truncate output to avoid context overflow. Built-in limit: 50KB / 2000 lines.\n\n```typescript\nimport {\n  truncateHead, truncateTail, formatSize,\n  DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES,\n} from \"@gsd/pi-coding-agent\";\n\nasync execute(toolCallId, params, signal, onUpdate, ctx) {\n  const output = await runCommand();\n  const truncation = truncateHead(output, {\n    maxLines: DEFAULT_MAX_LINES,\n    maxBytes: DEFAULT_MAX_BYTES,\n  });\n\n  let result = truncation.content;\n  if (truncation.truncated) {\n    const tempFile = writeTempFile(output);\n    result += `\\n\\n[Output truncated: ${truncation.outputLines}/${truncation.totalLines} lines`;\n    result += ` (${formatSize(truncation.outputBytes)}/${formatSize(truncation.totalBytes)}).`;\n    result += ` Full output: ${tempFile}]`;\n  }\n  return { content: [{ type: \"text\", text: result }] };\n}\n```\n\nUse `truncateHead` when beginning matters (search results, file reads). Use `truncateTail` when end matters (logs, command output).\n</output_truncation>\n\n<signaling_errors>\nThrow to signal an error (sets `isError: true`). Returning a value never sets error flag.\n\n```typescript\nasync execute(toolCallId, params) {\n  if (!isValid(params.input)) {\n    throw new Error(`Invalid input: ${params.input}`);\n  }\n  return { content: [{ type: \"text\", text: \"OK\" }], details: {} };\n}\n```\n</signaling_errors>\n\n<dynamic_registration>\nTools can be registered at any time — during load, in `session_start`, in command handlers. Available immediately without `/reload`.\n\n```typescript\npi.on(\"session_start\", async (_event, ctx) => {\n  pi.registerTool({ name: \"dynamic_tool\", ... });\n});\n```\n\nUse `pi.setActiveTools(names)` to enable/disable tools at runtime.\n</dynamic_registration>\n\n<overriding_builtins>\nRegister a tool with the same name as a built-in (`read`, `bash`, `edit`, `write`, `grep`, `find`, `ls`) to override it. **Must match exact result shape including `details` type.**\n\n```typescript\nimport { createReadTool } from \"@gsd/pi-coding-agent\";\n\npi.registerTool({\n  name: \"read\",\n  label: \"Read (Logged)\",\n  description: \"Read file contents with logging\",\n  parameters: Type.Object({\n    path: Type.String(),\n    offset: Type.Optional(Type.Number()),\n    limit: Type.Optional(Type.Number()),\n  }),\n  async execute(toolCallId, params, signal, onUpdate, ctx) {\n    console.log(`[AUDIT] Reading: ${params.path}`);\n    const builtIn = createReadTool(ctx.cwd);\n    return builtIn.execute(toolCallId, params, signal, onUpdate);\n  },\n  // Omit renderCall/renderResult to use built-in renderer\n});\n```\n\nStart with no built-in tools: `gsd --no-tools -e ./my-extension.ts`\n</overriding_builtins>\n\n<multiple_tools>\nOne extension can register multiple tools with shared state:\n\n```typescript\nexport default function (pi: ExtensionAPI) {\n  let connection = null;\n\n  pi.registerTool({ name: \"db_connect\", ... });\n  pi.registerTool({ name: \"db_query\", ... });\n  pi.registerTool({ name: \"db_close\", ... });\n\n  pi.on(\"session_shutdown\", async () => {\n    connection?.close();\n  });\n}\n```\n</multiple_tools>\n\n<path_normalization>\nSome models add `@` prefix to path arguments. Strip it:\n\n```typescript\nasync execute(toolCallId, params, signal, onUpdate, ctx) {\n  let path = params.path;\n  if (path.startsWith(\"@\")) path = path.slice(1);\n  // ...\n}\n```\n</path_normalization>\n","isInternal":false,"tokens":1381,"sizeBytes":5553},{"name":"custom-ui.md","path":"src/resources/skills/create-gsd-extension/references/custom-ui.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/custom-ui.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<overview>\nComplete custom UI reference — dialogs, persistent elements, custom components, overlays, custom editors, built-in components, keyboard input, performance, theming, and common mistakes.\n</overview>\n\n<ui_architecture>\n```\n┌─────────────────────────────────────────────────┐\n│  Custom Header (ctx.ui.setHeader)               │\n├─────────────────────────────────────────────────┤\n│  Message Area                                   │\n│  - User/assistant messages                      │\n│  - Tool calls ◄── renderCall/renderResult       │\n│  - Custom messages ◄── registerMessageRenderer  │\n├─────────────────────────────────────────────────┤\n│  Widgets (above editor) ◄── ctx.ui.setWidget    │\n├─────────────────────────────────────────────────┤\n│  Editor ◄── ctx.ui.custom() / setEditorComponent│\n├─────────────────────────────────────────────────┤\n│  Widgets (below editor) ◄── ctx.ui.setWidget    │\n├─────────────────────────────────────────────────┤\n│  Footer ◄── ctx.ui.setFooter / setStatus        │\n└─────────────────────────────────────────────────┘\n  ┌─────────────────────┐\n  │  Overlay (floating)  │ ◄── ctx.ui.custom({ overlay })\n  └─────────────────────┘\n```\n\n**11 ways to get UI on screen:**\n\n| Method | Blocks? | Replaces editor? |\n|--------|---------|-------------------|\n| `ctx.ui.select/confirm/input/editor` | Yes | Temporarily |\n| `ctx.ui.notify` | No | No |\n| `ctx.ui.setStatus` | No | No (footer) |\n| `ctx.ui.setWidget` | No | No |\n| `ctx.ui.setFooter` | No | No (replaces footer) |\n| `ctx.ui.setHeader` | No | No (replaces header) |\n| `ctx.ui.custom()` | Yes | Temporarily |\n| `ctx.ui.custom({overlay})` | Yes | No (renders on top) |\n| `ctx.ui.setEditorComponent` | No | Yes (permanently) |\n| `renderCall/renderResult` | No | No (inline in messages) |\n| `registerMessageRenderer` | No | No (inline in messages) |\n</ui_architecture>\n\n<component_interface>\nEvery visual element implements:\n\n```typescript\ninterface Component {\n  render(width: number): string[];   // Required — each line ≤ width visible chars\n  handleInput?(data: string): void;  // Optional — receive keyboard input\n  wantsKeyRelease?: boolean;         // Optional — receive key release events (Kitty protocol)\n  invalidate(): void;                // Required — clear cached render state\n}\n```\n\n**Render contract:**\n- Return array of strings, one per line\n- Each string MUST NOT exceed `width` in visible characters\n- ANSI escape codes don't count toward visible width\n- **Styles are reset at end of each line** — reapply per line\n- Return `[]` for zero-height component\n\n**Invalidation contract:**\n- Clear ALL cached render output\n- Clear any pre-baked themed strings\n- Call `super.invalidate()` if extending a built-in component\n</component_interface>\n\n<dialogs>\nBlocking dialog methods on `ctx.ui`:\n\n```typescript\nconst choice = await ctx.ui.select(\"Pick one:\", [\"A\", \"B\", \"C\"]);       // string | undefined\nconst ok = await ctx.ui.confirm(\"Delete?\", \"This cannot be undone\");    // boolean\nconst name = await ctx.ui.input(\"Name:\", \"placeholder\");                // string | undefined\nconst text = await ctx.ui.editor(\"Edit:\", \"prefilled text\");            // string | undefined\n\n// Timed auto-dismiss with countdown\nconst ok = await ctx.ui.confirm(\"Proceed?\", \"Auto-continues in 5s\", { timeout: 5000 });\n// Returns false on timeout, undefined for select/input\n\n// Manual dismissal with AbortSignal (distinguish timeout from cancel)\nconst controller = new AbortController();\nconst timeoutId = setTimeout(() => controller.abort(), 5000);\nconst ok = await ctx.ui.confirm(\"Timed\", \"Auto-cancels in 5s\", { signal: controller.signal });\nclearTimeout(timeoutId);\nif (controller.signal.aborted) { /* timed out */ }\n```\n</dialogs>\n\n<persistent_ui>\n```typescript\n// Footer status (multiple extensions can set independent entries)\nctx.ui.setStatus(\"my-ext\", \"● Active\");\nctx.ui.setStatus(\"my-ext\", undefined);  // Clear\n\n// Widgets\nctx.ui.setWidget(\"my-id\", [\"Line 1\", \"Line 2\"]);                       // Above editor\nctx.ui.setWidget(\"my-id\", [\"Below\"], { placement: \"belowEditor\" });    // Below editor\nctx.ui.setWidget(\"my-id\", (_tui, theme) => ({                          // Themed\n  render: () => [theme.fg(\"accent\", \"Styled\")],\n  invalidate: () => {},\n}));\nctx.ui.setWidget(\"my-id\", undefined);  // Clear\n\n// Working message during streaming\nctx.ui.setWorkingMessage(\"Analyzing code...\");\nctx.ui.setWorkingMessage();  // Restore default\n\n// Custom footer (full replacement)\nctx.ui.setFooter((tui, theme, footerData) => ({\n  render(width) {\n    const branch = footerData.getGitBranch();          // Only available here\n    const statuses = footerData.getExtensionStatuses(); // All setStatus values\n    return [truncateToWidth(`${branch} | model`, width)];\n  },\n  invalidate() {},\n  dispose: footerData.onBranchChange(() => tui.requestRender()),  // Reactive\n}));\nctx.ui.setFooter(undefined);  // Restore default\n\n// Custom header\nctx.ui.setHeader((tui, theme) => ({\n  render(width) { return [theme.fg(\"accent\", theme.bold(\"My Header\"))]; },\n  invalidate() {},\n}));\n\n// Editor control\nctx.ui.setEditorText(\"Prefill\");\nconst current = ctx.ui.getEditorText();\nctx.ui.pasteToEditor(\"pasted content\");  // Triggers paste handling\n\n// Tool expansion\nctx.ui.setToolsExpanded(true);\nconst expanded = ctx.ui.getToolsExpanded();\n\n// Theme management\nconst themes = ctx.ui.getAllThemes();\nctx.ui.setTheme(\"light\");\nctx.ui.theme.fg(\"accent\", \"text\");  // Access current theme\n```\n</persistent_ui>\n\n<custom_components>\n`ctx.ui.custom()` temporarily replaces the editor. Returns a value when `done()` is called.\n\n**Factory callback args:**\n\n| Argument | Type | Purpose |\n|----------|------|---------|\n| `tui` | `TUI` | `tui.requestRender()` triggers re-render after state changes |\n| `theme` | `Theme` | Current theme for styling |\n| `keybindings` | `KeybindingsManager` | App keybinding config |\n| `done` | `(value: T) => void` | Close component and return value |\n\n**Inline pattern:**\n```typescript\nconst result = await ctx.ui.custom<string | null>((tui, theme, keybindings, done) => ({\n  render(width: number): string[] {\n    return [truncateToWidth(\"Press Enter to confirm, Escape to cancel\", width)];\n  },\n  handleInput(data: string) {\n    if (matchesKey(data, Key.enter)) done(\"confirmed\");\n    if (matchesKey(data, Key.escape)) done(null);\n  },\n  invalidate() {},\n}));\n```\n\n**Class-based pattern (recommended for complex UI):**\n```typescript\nclass MyComponent {\n  private selected = 0;\n  private cachedWidth?: number;\n  private cachedLines?: string[];\n\n  constructor(\n    private tui: { requestRender: () => void },\n    private theme: Theme,\n    private items: string[],\n    private done: (value: string | null) => void,\n  ) {}\n\n  handleInput(data: string) {\n    if (matchesKey(data, Key.up) && this.selected > 0) this.selected--;\n    else if (matchesKey(data, Key.down) && this.selected < this.items.length - 1) this.selected++;\n    else if (matchesKey(data, Key.enter)) { this.done(this.items[this.selected]); return; }\n    else if (matchesKey(data, Key.escape)) { this.done(null); return; }\n    else return;\n    this.invalidate();\n    this.tui.requestRender();\n  }\n\n  render(width: number): string[] {\n    if (this.cachedLines && this.cachedWidth === width) return this.cachedLines;\n    this.cachedLines = this.items.map((item, i) =>\n      truncateToWidth((i === this.selected ? \"> \" : \"  \") + item, width)\n    );\n    this.cachedWidth = width;\n    return this.cachedLines;\n  }\n\n  invalidate() { this.cachedWidth = undefined; this.cachedLines = undefined; }\n}\n\nconst result = await ctx.ui.custom<string | null>((tui, theme, _kb, done) =>\n  new MyComponent(tui, theme, [\"A\", \"B\", \"C\"], done)\n);\n```\n\n**Composing with built-in components:**\n```typescript\nconst result = await ctx.ui.custom<string | null>((tui, theme, _kb, done) => {\n  const container = new Container();\n  container.addChild(new DynamicBorder((s: string) => theme.fg(\"accent\", s)));\n  container.addChild(new Text(theme.fg(\"accent\", theme.bold(\"Title\")), 1, 0));\n\n  const selectList = new SelectList(items, 10, {\n    selectedPrefix: (t) => theme.fg(\"accent\", t),\n    selectedText: (t) => theme.fg(\"accent\", t),\n    description: (t) => theme.fg(\"muted\", t),\n    scrollInfo: (t) => theme.fg(\"dim\", t),\n    noMatch: (t) => theme.fg(\"warning\", t),\n  });\n  selectList.onSelect = (item) => done(item.value);\n  selectList.onCancel = () => done(null);\n  container.addChild(selectList);\n\n  return {\n    render: (w) => container.render(w),\n    invalidate: () => container.invalidate(),\n    handleInput: (data) => { selectList.handleInput(data); tui.requestRender(); },\n  };\n});\n```\n</custom_components>\n\n<overlays>\nFloating modals rendered on top of everything:\n\n```typescript\nconst result = await ctx.ui.custom<string | null>(\n  (tui, theme, _kb, done) => new MyDialog({ onClose: done }),\n  {\n    overlay: true,\n    overlayOptions: {\n      anchor: \"center\",         // 9 positions (see below)\n      width: \"50%\",             // number = columns, string = percentage\n      minWidth: 40,\n      maxHeight: \"80%\",\n      margin: 2,                // All sides, or { top, right, bottom, left }\n      offsetX: 0, offsetY: 0,  // Fine-tune position\n      visible: (w, h) => w >= 80,  // Hide on narrow terminals\n    },\n    onHandle: (handle) => {\n      // handle.setHidden(true/false) — temporarily hide\n      // handle.hide() — permanently remove\n    },\n  }\n);\n```\n\n**Anchor positions:**\n```\ntop-left      top-center      top-right\nleft-center      center      right-center\nbottom-left  bottom-center  bottom-right\n```\n\n**Stacked overlays:** Multiple overlays stack (newest on top). Closing one gives focus to the one below.\n\n**⚠️ Overlay lifecycle:** Components are disposed when closed. Never reuse references — create fresh instances each time.\n</overlays>\n\n<custom_editor>\nReplace the main input editor permanently:\n\n```typescript\nimport { CustomEditor } from \"@gsd/pi-coding-agent\";\n\nclass VimEditor extends CustomEditor {\n  private mode: \"normal\" | \"insert\" = \"insert\";\n\n  handleInput(data: string): void {\n    if (matchesKey(data, \"escape\") && this.mode === \"insert\") {\n      this.mode = \"normal\"; return;\n    }\n    if (this.mode === \"insert\") { super.handleInput(data); return; }\n    switch (data) {\n      case \"i\": this.mode = \"insert\"; return;\n      case \"h\": super.handleInput(\"\\x1b[D\"); return;  // Left\n      case \"j\": super.handleInput(\"\\x1b[B\"); return;  // Down\n      case \"k\": super.handleInput(\"\\x1b[A\"); return;  // Up\n      case \"l\": super.handleInput(\"\\x1b[C\"); return;  // Right\n    }\n    if (data.length === 1 && data.charCodeAt(0) >= 32) return;  // Block printable in normal\n    super.handleInput(data);\n  }\n}\n\nctx.ui.setEditorComponent((_tui, theme, keybindings) => new VimEditor(theme, keybindings));\nctx.ui.setEditorComponent(undefined);  // Restore default\n```\n\n**Critical:** Extend `CustomEditor` (NOT `Editor`) to get app keybindings (escape to abort, ctrl+d, model switching).\n</custom_editor>\n\n<built_in_components>\n**From `@gsd/pi-tui`:**\n\n| Component | Constructor | Purpose |\n|-----------|-------------|---------|\n| `Text` | `new Text(content, paddingX, paddingY, bgFn?)` | Multi-line text with word wrap |\n| `Box` | `new Box(paddingX, paddingY, bgFn)` | Container with padding+background, `.addChild()` |\n| `Container` | `new Container()` | Vertical stack, `.addChild()`, `.removeChild()`, `.clear()` |\n| `Spacer` | `new Spacer(lines)` | Empty vertical space |\n| `Markdown` | `new Markdown(content, padX, padY, getMarkdownTheme())` | Rendered markdown with syntax highlighting |\n| `Image` | `new Image(base64, mimeType, theme, opts?)` | Image rendering (Kitty, iTerm2) |\n| `SelectList` | `new SelectList(items, maxVisible, themeOpts)` | Interactive selection with search and scrolling |\n| `SettingsList` | `new SettingsList(items, maxVisible, theme, onChange, onClose, opts?)` | Toggle settings with left/right arrows |\n| `Input` | `new Input()` | Text input field |\n| `Editor` | `new Editor(tui, editorTheme)` | Multi-line editor with undo |\n\n**SelectList usage:**\n```typescript\nconst items: SelectItem[] = [\n  { value: \"opt1\", label: \"Option 1\", description: \"First option\" },\n  { value: \"opt2\", label: \"Option 2\" },\n];\nconst selectList = new SelectList(items, 10, {\n  selectedPrefix: (t) => theme.fg(\"accent\", t),\n  selectedText: (t) => theme.fg(\"accent\", t),\n  description: (t) => theme.fg(\"muted\", t),\n  scrollInfo: (t) => theme.fg(\"dim\", t),\n  noMatch: (t) => theme.fg(\"warning\", t),\n});\nselectList.onSelect = (item) => { /* item.value */ };\nselectList.onCancel = () => { /* escape pressed */ };\n```\n\n**SettingsList usage:**\n```typescript\nconst items: SettingItem[] = [\n  { id: \"verbose\", label: \"Verbose mode\", currentValue: \"off\", values: [\"on\", \"off\"] },\n  { id: \"theme\", label: \"Theme\", currentValue: \"dark\", values: [\"dark\", \"light\", \"auto\"] },\n];\nconst settings = new SettingsList(items, 15, getSettingsListTheme(),\n  (id, newValue) => { /* setting changed */ },\n  () => { /* close requested */ },\n  { enableSearch: true },\n);\n```\n\n**From `@gsd/pi-coding-agent`:**\n\n| Component | Constructor | Purpose |\n|-----------|-------------|---------|\n| `DynamicBorder` | `new DynamicBorder((s: string) => theme.fg(\"accent\", s))` | Border line |\n| `BorderedLoader` | — | Spinner with cancel support |\n| `CustomEditor` | `new CustomEditor(theme, keybindings)` | Base class for custom editors |\n</built_in_components>\n\n<keyboard_input>\n```typescript\nimport { matchesKey, Key } from \"@gsd/pi-tui\";\n\nhandleInput(data: string) {\n  // Basic keys\n  if (matchesKey(data, Key.up)) {}\n  if (matchesKey(data, Key.down)) {}\n  if (matchesKey(data, Key.enter)) {}\n  if (matchesKey(data, Key.escape)) {}\n  if (matchesKey(data, Key.tab)) {}\n  if (matchesKey(data, Key.space)) {}\n  if (matchesKey(data, Key.backspace)) {}\n  if (matchesKey(data, Key.home)) {}\n  if (matchesKey(data, Key.end)) {}\n\n  // With modifiers\n  if (matchesKey(data, Key.ctrl(\"c\"))) {}\n  if (matchesKey(data, Key.shift(\"tab\"))) {}\n  if (matchesKey(data, Key.alt(\"left\"))) {}\n  if (matchesKey(data, Key.ctrlShift(\"p\"))) {}\n\n  // String format also works: \"enter\", \"ctrl+c\", \"shift+tab\"\n\n  // Printable character detection\n  if (data.length === 1 && data.charCodeAt(0) >= 32) {\n    // Letter, number, symbol\n  }\n}\n```\n\n**handleInput contract:**\n1. Check for your keys\n2. Update state\n3. Call `this.invalidate()` if render output changes\n4. Call `tui.requestRender()` to trigger re-render\n</keyboard_input>\n\n<line_width_rule>\n**Cardinal rule: each line from render() must not exceed `width` visible characters.**\n\n```typescript\nimport { visibleWidth, truncateToWidth, wrapTextWithAnsi } from \"@gsd/pi-tui\";\n\nvisibleWidth(\"\\x1b[32mHello\\x1b[0m\");  // Returns 5 (ignores ANSI codes)\ntruncateToWidth(\"Very long text here\", 10);         // \"Very lo...\"\ntruncateToWidth(\"Very long text here\", 10, \"\");      // \"Very long \" (no ellipsis)\nwrapTextWithAnsi(\"\\x1b[32mLong green text\\x1b[0m\", 10);  // Word wrap preserving ANSI\n```\n\nIf lines exceed `width`, terminal wraps cause visual corruption.\n</line_width_rule>\n\n<performance_caching>\nAlways cache render output:\n\n```typescript\nclass CachedComponent {\n  private cachedWidth?: number;\n  private cachedLines?: string[];\n\n  render(width: number): string[] {\n    if (this.cachedLines && this.cachedWidth === width) return this.cachedLines;\n    const lines = this.computeLines(width);\n    this.cachedWidth = width;\n    this.cachedLines = lines;\n    return lines;\n  }\n\n  invalidate() { this.cachedWidth = undefined; this.cachedLines = undefined; }\n}\n```\n\n**Update cycle:** State changes → `invalidate()` → `tui.requestRender()` → `render(width)` called\n\n**Game loop pattern** (real-time updates):\n```typescript\nthis.interval = setInterval(() => {\n  this.tick();\n  this.version++;\n  this.tui.requestRender();\n}, 100);  // 10 FPS\n\n// Clean up in dispose()\nclearInterval(this.interval);\n```\n</performance_caching>\n\n<theme_colors>\nAlways use theme from callback params, never import directly.\n\n**All foreground colors:**\n\n| Category | Colors |\n|----------|--------|\n| General | `text`, `accent`, `muted`, `dim` |\n| Status | `success`, `error`, `warning` |\n| Borders | `border`, `borderAccent`, `borderMuted` |\n| Messages | `userMessageText`, `customMessageText`, `customMessageLabel` |\n| Tools | `toolTitle`, `toolOutput` |\n| Diffs | `toolDiffAdded`, `toolDiffRemoved`, `toolDiffContext` |\n| Markdown | `mdHeading`, `mdLink`, `mdLinkUrl`, `mdCode`, `mdCodeBlock`, `mdCodeBlockBorder`, `mdQuote`, `mdQuoteBorder`, `mdHr`, `mdListBullet` |\n| Syntax | `syntaxComment`, `syntaxKeyword`, `syntaxFunction`, `syntaxVariable`, `syntaxString`, `syntaxNumber`, `syntaxType`, `syntaxOperator`, `syntaxPunctuation` |\n| Thinking | `thinkingOff`, `thinkingMinimal`, `thinkingLow`, `thinkingMedium`, `thinkingHigh`, `thinkingXhigh` |\n\n**All background colors:** `selectedBg`, `userMessageBg`, `customMessageBg`, `toolPendingBg`, `toolSuccessBg`, `toolErrorBg`\n\n**Syntax highlighting:**\n```typescript\nimport { highlightCode, getLanguageFromPath } from \"@gsd/pi-coding-agent\";\nconst lang = getLanguageFromPath(\"/file.rs\");  // \"rust\"\nconst highlighted = highlightCode(code, lang, theme);\n```\n</theme_colors>\n\n<common_mistakes>\n1. **Lines exceed width** → Visual corruption. Use `truncateToWidth()` on every line.\n2. **Forgetting `tui.requestRender()`** → UI doesn't update. Call after invalidate().\n3. **Importing theme directly** → Wrong colors after theme switch. Use theme from callback.\n4. **Not typing DynamicBorder param** → `new DynamicBorder((s: string) => theme.fg(\"accent\", s))`.\n5. **Reusing disposed overlay components** → Create fresh instances each time.\n6. **Styles bleeding across lines** → TUI resets per line. Reapply styles, or use `wrapTextWithAnsi()`.\n7. **Not implementing invalidate()** → Theme changes don't take effect.\n8. **Forgetting super.invalidate()** → `override invalidate() { super.invalidate(); /* cleanup */ }`\n9. **Timer not cleaned up** → Call `clearInterval` before `done()`.\n10. **Using ctx.ui in non-interactive mode** → Check `ctx.hasUI` first.\n</common_mistakes>\n","isInternal":false,"tokens":4699,"sizeBytes":18994},{"name":"events-reference.md","path":"src/resources/skills/create-gsd-extension/references/events-reference.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/events-reference.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<overview>\nComplete event reference with handler signatures, return types, and type narrowing utilities.\n</overview>\n\n<event_categories>\n\n**Session events:** `session_start`, `session_before_switch`, `session_switch`, `session_before_fork`, `session_fork`, `session_before_compact`, `session_compact`, `session_before_tree`, `session_tree`, `session_shutdown`\n\n**Agent events:** `before_agent_start`, `agent_start`, `agent_end`, `turn_start`, `turn_end`, `context`, `before_provider_request`, `message_start`, `message_update`, `message_end`\n\n**Tool events:** `tool_call`, `tool_execution_start`, `tool_execution_update`, `tool_execution_end`, `tool_result`\n\n**Input events:** `input`\n\n**Model events:** `model_select`\n\n**User bash events:** `user_bash`\n\n**Special:** `session_directory` (CLI startup only, no `ctx` — receives only event)\n\n</event_categories>\n\n<handler_signature>\n```typescript\npi.on(\"event_name\", async (event, ctx: ExtensionContext) => {\n  // event — typed payload for this event\n  // ctx — access to UI, session, model, control flow\n  // Return undefined for no action, or a typed response\n});\n```\n</handler_signature>\n\n<key_events>\n\n**before_agent_start** — Fired after user prompt, before agent loop. Primary hook for context injection and system prompt modification.\n```typescript\npi.on(\"before_agent_start\", async (event, ctx) => {\n  // event.prompt — user's prompt text\n  // event.images — attached images\n  // event.systemPrompt — current system prompt\n  return {\n    message: { customType: \"my-ext\", content: \"Extra context\", display: true },\n    systemPrompt: event.systemPrompt + \"\\n\\nExtra instructions...\",\n  };\n});\n```\n\n**tool_call** — Fired before tool executes. Can block.\n```typescript\nimport { isToolCallEventType } from \"@gsd/pi-coding-agent\";\n\npi.on(\"tool_call\", async (event, ctx) => {\n  if (isToolCallEventType(\"bash\", event)) {\n    // event.input is typed as { command: string; timeout?: number }\n    if (event.input.command.includes(\"rm -rf\")) {\n      return { block: true, reason: \"Dangerous command\" };\n    }\n  }\n});\n```\n\n**tool_result** — Fired after tool executes. Can modify result. Handlers chain like middleware.\n```typescript\nimport { isToolResultEventType } from \"@gsd/pi-coding-agent\";\n\npi.on(\"tool_result\", async (event, ctx) => {\n  if (isToolResultEventType(\"bash\", event)) {\n    // event.details is typed as BashToolDetails\n  }\n  // Return partial patch: { content, details, isError }\n  // Omitted fields keep current values\n});\n```\n\n**context** — Fired before each LLM call. Modify messages non-destructively.\n```typescript\npi.on(\"context\", async (event, ctx) => {\n  // event.messages is a deep copy — safe to modify\n  const filtered = event.messages.filter(m => !shouldPrune(m));\n  return { messages: filtered };\n});\n```\n\n**input** — Fired when user input is received, before skill/template expansion.\n```typescript\npi.on(\"input\", async (event, ctx) => {\n  // event.text — raw input\n  // event.source — \"interactive\", \"rpc\", or \"extension\"\n  if (event.text.startsWith(\"?quick \"))\n    return { action: \"transform\", text: `Respond briefly: ${event.text.slice(7)}` };\n  return { action: \"continue\" };\n});\n```\n\n**model_select** — Fired when model changes.\n```typescript\npi.on(\"model_select\", async (event, ctx) => {\n  // event.model, event.previousModel, event.source (\"set\"|\"cycle\"|\"restore\")\n});\n```\n\n</key_events>\n\n<type_narrowing>\nBuilt-in type guards for tool events:\n\n```typescript\nimport { isToolCallEventType, isToolResultEventType } from \"@gsd/pi-coding-agent\";\n\n// Tool calls — narrows event.input type\nif (isToolCallEventType(\"bash\", event)) { /* event.input: { command, timeout? } */ }\nif (isToolCallEventType(\"read\", event)) { /* event.input: { path, offset?, limit? } */ }\nif (isToolCallEventType(\"write\", event)) { /* event.input: { path, content } */ }\nif (isToolCallEventType(\"edit\", event)) { /* event.input: { path, oldText, newText } */ }\n\n// Tool results — narrows event.details type\nif (isToolResultEventType(\"bash\", event)) { /* event.details: BashToolDetails */ }\n```\n\nFor custom tools, export your input type and use explicit type params:\n```typescript\nif (isToolCallEventType<\"my_tool\", MyToolInput>(\"my_tool\", event)) {\n  event.input.action; // typed\n}\n```\n</type_narrowing>\n","isInternal":false,"tokens":1057,"sizeBytes":4289},{"name":"extension-lifecycle.md","path":"src/resources/skills/create-gsd-extension/references/extension-lifecycle.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/extension-lifecycle.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fextension-lifecycle.md -->","isInternal":false,"tokens":599,"sizeBytes":2623},{"name":"extensionapi-reference.md","path":"src/resources/skills/create-gsd-extension/references/extensionapi-reference.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/extensionapi-reference.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fextensionapi-reference.md -->","isInternal":false,"tokens":632,"sizeBytes":2554},{"name":"extensioncontext-reference.md","path":"src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/extensioncontext-reference.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fextensioncontext-reference.md -->","isInternal":false,"tokens":544,"sizeBytes":2278},{"name":"key-rules-gotchas.md","path":"src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/key-rules-gotchas.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fkey-rules-gotchas.md -->","isInternal":false,"tokens":531,"sizeBytes":2128},{"name":"mode-behavior.md","path":"src/resources/skills/create-gsd-extension/references/mode-behavior.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/mode-behavior.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fmode-behavior.md -->","isInternal":false,"tokens":290,"sizeBytes":1127},{"name":"model-provider-management.md","path":"src/resources/skills/create-gsd-extension/references/model-provider-management.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/model-provider-management.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fmodel-provider-management.md -->","isInternal":false,"tokens":679,"sizeBytes":2616},{"name":"packaging-distribution.md","path":"src/resources/skills/create-gsd-extension/references/packaging-distribution.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/packaging-distribution.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fpackaging-distribution.md -->","isInternal":false,"tokens":374,"sizeBytes":1262},{"name":"remote-execution-overrides.md","path":"src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fremote-execution-overrides.md -->","isInternal":false,"tokens":650,"sizeBytes":2678},{"name":"state-management.md","path":"src/resources/skills/create-gsd-extension/references/state-management.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/state-management.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fstate-management.md -->","isInternal":false,"tokens":570,"sizeBytes":2318},{"name":"system-prompt-modification.md","path":"src/resources/skills/create-gsd-extension/references/system-prompt-modification.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/references/system-prompt-modification.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Freferences%2Fsystem-prompt-modification.md -->","isInternal":false,"tokens":357,"sizeBytes":1534},{"name":"SKILL.md","path":"src/resources/skills/create-gsd-extension/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/SKILL.md","title":"create-gsd-extension","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2FSKILL.md -->","frontmatter":{"name":"create-gsd-extension","description":"Create, debug, and iterate on GSD extensions (TypeScript modules that add tools, commands, event hooks, custom UI, and providers to GSD). Use when asked to build an extension, add a tool the LLM can call, register a slash command, hook into GSD events, create custom TUI components, or modify GSD behavior. Triggers on \"create extension\", \"build extension\", \"add a tool\", \"register command\", \"hook into gsd\", \"custom tool\", \"gsd plugin\", \"gsd extension\"."},"isInternal":false,"tokens":1305,"sizeBytes":5394},{"name":"add-capability.md","path":"src/resources/skills/create-gsd-extension/workflows/add-capability.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/workflows/add-capability.md","title":"Workflows Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Fworkflows%2Fadd-capability.md -->","isInternal":false,"tokens":388,"sizeBytes":1730},{"name":"create-extension.md","path":"src/resources/skills/create-gsd-extension/workflows/create-extension.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/workflows/create-extension.md","title":"Workflows Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Fworkflows%2Fcreate-extension.md -->","isInternal":false,"tokens":1356,"sizeBytes":5518},{"name":"debug-extension.md","path":"src/resources/skills/create-gsd-extension/workflows/debug-extension.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-gsd-extension/workflows/debug-extension.md","title":"Workflows Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-gsd-extension%2Fworkflows%2Fdebug-extension.md -->","isInternal":false,"tokens":588,"sizeBytes":2445},{"name":"SKILL.md","path":"src/resources/skills/create-mcp-server/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-mcp-server/SKILL.md","title":"create-mcp-server","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-mcp-server%2FSKILL.md -->","frontmatter":{"name":"create-mcp-server","description":"Build, iterate, and evaluate Model Context Protocol (MCP) servers that expose external services as tools an LLM can call. Use when asked to \"build an MCP server\", \"create an MCP tool\", \"wrap this API as MCP\", \"expose X to Claude\", or when extending GSD with custom tool integrations. Covers research, schema/tool design, error handling, pagination, testing via MCP Inspector, and producing a 10-question eval set that proves the server actually enables real work."},"isInternal":false,"tokens":1672,"sizeBytes":7118},{"name":"api-security.md","path":"src/resources/skills/create-skill/references/api-security.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/references/api-security.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fapi-security.md -->","isInternal":false,"tokens":1544,"sizeBytes":6193},{"name":"be-clear-and-direct.md","path":"src/resources/skills/create-skill/references/be-clear-and-direct.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/references/be-clear-and-direct.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fbe-clear-and-direct.md -->","isInternal":false,"tokens":2918,"sizeBytes":13030},{"name":"common-patterns.md","path":"src/resources/skills/create-skill/references/common-patterns.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/references/common-patterns.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fcommon-patterns.md -->","isInternal":false,"tokens":3287,"sizeBytes":14431},{"name":"core-principles.md","path":"src/resources/skills/create-skill/references/core-principles.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/references/core-principles.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fcore-principles.md -->","isInternal":false,"tokens":2737,"sizeBytes":12695},{"name":"executable-code.md","path":"src/resources/skills/create-skill/references/executable-code.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/references/executable-code.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fexecutable-code.md -->","isInternal":false,"tokens":1023,"sizeBytes":4378},{"name":"gsd-skill-ecosystem.md","path":"src/resources/skills/create-skill/references/gsd-skill-ecosystem.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fgsd-skill-ecosystem.md -->","isInternal":false,"tokens":689,"sizeBytes":3157},{"name":"iteration-and-testing.md","path":"src/resources/skills/create-skill/references/iteration-and-testing.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/references/iteration-and-testing.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fiteration-and-testing.md -->","isInternal":false,"tokens":3000,"sizeBytes":13496},{"name":"recommended-structure.md","path":"src/resources/skills/create-skill/references/recommended-structure.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/references/recommended-structure.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Frecommended-structure.md -->","isInternal":false,"tokens":971,"sizeBytes":4006},{"name":"skill-structure.md","path":"src/resources/skills/create-skill/references/skill-structure.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/references/skill-structure.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fskill-structure.md -->","isInternal":false,"tokens":2612,"sizeBytes":11177},{"name":"use-xml-tags.md","path":"src/resources/skills/create-skill/references/use-xml-tags.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/references/use-xml-tags.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fuse-xml-tags.md -->","isInternal":false,"tokens":2603,"sizeBytes":11455},{"name":"using-scripts.md","path":"src/resources/skills/create-skill/references/using-scripts.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/references/using-scripts.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fusing-scripts.md -->","isInternal":false,"tokens":690,"sizeBytes":3023},{"name":"using-templates.md","path":"src/resources/skills/create-skill/references/using-templates.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/references/using-templates.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fusing-templates.md -->","isInternal":false,"tokens":655,"sizeBytes":2924},{"name":"workflows-and-validation.md","path":"src/resources/skills/create-skill/references/workflows-and-validation.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/references/workflows-and-validation.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Freferences%2Fworkflows-and-validation.md -->","isInternal":false,"tokens":2695,"sizeBytes":11845},{"name":"SKILL.md","path":"src/resources/skills/create-skill/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/SKILL.md","title":"create-skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2FSKILL.md -->","frontmatter":{"name":"create-skill","description":"Expert guidance for creating, writing, building, and refining GSD skills. Use when working with SKILL.md files, authoring new skills, improving existing skills, or understanding skill structure and best practices."},"isInternal":false,"tokens":1445,"sizeBytes":6306},{"name":"router-skill.md","path":"src/resources/skills/create-skill/templates/router-skill.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/templates/router-skill.md","title":"Templates Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Ftemplates%2Frouter-skill.md -->","isInternal":false,"tokens":390,"sizeBytes":1494},{"name":"simple-skill.md","path":"src/resources/skills/create-skill/templates/simple-skill.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/templates/simple-skill.md","title":"Templates Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Ftemplates%2Fsimple-skill.md -->","isInternal":false,"tokens":152,"sizeBytes":636},{"name":"add-reference.md","path":"src/resources/skills/create-skill/workflows/add-reference.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/workflows/add-reference.md","title":"Workflows Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fadd-reference.md -->","isInternal":false,"tokens":532,"sizeBytes":2272},{"name":"add-script.md","path":"src/resources/skills/create-skill/workflows/add-script.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/workflows/add-script.md","title":"Workflows Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fadd-script.md -->","isInternal":false,"tokens":521,"sizeBytes":2155},{"name":"add-template.md","path":"src/resources/skills/create-skill/workflows/add-template.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/workflows/add-template.md","title":"Workflows Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fadd-template.md -->","isInternal":false,"tokens":429,"sizeBytes":1926},{"name":"add-workflow.md","path":"src/resources/skills/create-skill/workflows/add-workflow.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/workflows/add-workflow.md","title":"Workflows Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fadd-workflow.md -->","isInternal":false,"tokens":720,"sizeBytes":2921},{"name":"audit-skill.md","path":"src/resources/skills/create-skill/workflows/audit-skill.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/workflows/audit-skill.md","title":"Workflows Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Faudit-skill.md -->","isInternal":false,"tokens":930,"sizeBytes":3710},{"name":"create-new-skill.md","path":"src/resources/skills/create-skill/workflows/create-new-skill.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/workflows/create-new-skill.md","title":"Workflows Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fcreate-new-skill.md -->","isInternal":false,"tokens":1388,"sizeBytes":5987},{"name":"get-guidance.md","path":"src/resources/skills/create-skill/workflows/get-guidance.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/workflows/get-guidance.md","title":"Workflows Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fget-guidance.md -->","isInternal":false,"tokens":704,"sizeBytes":3098},{"name":"upgrade-to-router.md","path":"src/resources/skills/create-skill/workflows/upgrade-to-router.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/workflows/upgrade-to-router.md","title":"Workflows Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fupgrade-to-router.md -->","isInternal":false,"tokens":913,"sizeBytes":3785},{"name":"verify-skill.md","path":"src/resources/skills/create-skill/workflows/verify-skill.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-skill/workflows/verify-skill.md","title":"Workflows Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-skill%2Fworkflows%2Fverify-skill.md -->","isInternal":false,"tokens":1268,"sizeBytes":5194},{"name":"feature-patterns.md","path":"src/resources/skills/create-workflow/references/feature-patterns.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-workflow/references/feature-patterns.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Freferences%2Ffeature-patterns.md -->","isInternal":false,"tokens":995,"sizeBytes":4201},{"name":"verification-policies.md","path":"src/resources/skills/create-workflow/references/verification-policies.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-workflow/references/verification-policies.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Freferences%2Fverification-policies.md -->","isInternal":false,"tokens":626,"sizeBytes":2715},{"name":"yaml-schema-v1.md","path":"src/resources/skills/create-workflow/references/yaml-schema-v1.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-workflow/references/yaml-schema-v1.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Freferences%2Fyaml-schema-v1.md -->","isInternal":false,"tokens":737,"sizeBytes":3063},{"name":"SKILL.md","path":"src/resources/skills/create-workflow/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-workflow/SKILL.md","title":"create-workflow","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2FSKILL.md -->","frontmatter":{"name":"create-workflow","description":"Conversational guide for creating valid YAML workflow definitions. Use when asked to \"create a workflow\", \"new workflow definition\", \"build a workflow\", \"workflow YAML\", \"define workflow steps\", or \"workflow from template\"."},"isInternal":false,"tokens":1609,"sizeBytes":6835},{"name":"blog-post-pipeline.yaml","path":"src/resources/skills/create-workflow/templates/blog-post-pipeline.yaml","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-workflow/templates/blog-post-pipeline.yaml","title":"Templates Skill","category":"anthropic-skill","format":"yaml","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Ftemplates%2Fblog-post-pipeline.yaml -->","isInternal":false,"tokens":385,"sizeBytes":1683},{"name":"code-audit.yaml","path":"src/resources/skills/create-workflow/templates/code-audit.yaml","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-workflow/templates/code-audit.yaml","title":"Templates Skill","category":"anthropic-skill","format":"yaml","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Ftemplates%2Fcode-audit.yaml -->","isInternal":false,"tokens":424,"sizeBytes":1895},{"name":"release-checklist.yaml","path":"src/resources/skills/create-workflow/templates/release-checklist.yaml","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-workflow/templates/release-checklist.yaml","title":"Templates Skill","category":"anthropic-skill","format":"yaml","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Ftemplates%2Frelease-checklist.yaml -->","isInternal":false,"tokens":488,"sizeBytes":2018},{"name":"workflow-definition.yaml","path":"src/resources/skills/create-workflow/templates/workflow-definition.yaml","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-workflow/templates/workflow-definition.yaml","title":"Templates Skill","category":"anthropic-skill","format":"yaml","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Ftemplates%2Fworkflow-definition.yaml -->","isInternal":false,"tokens":217,"sizeBytes":785},{"name":"create-from-scratch.md","path":"src/resources/skills/create-workflow/workflows/create-from-scratch.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-workflow/workflows/create-from-scratch.md","title":"Workflows Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Fworkflows%2Fcreate-from-scratch.md -->","isInternal":false,"tokens":980,"sizeBytes":4070},{"name":"create-from-template.md","path":"src/resources/skills/create-workflow/workflows/create-from-template.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/create-workflow/workflows/create-from-template.md","title":"Workflows Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fcreate-workflow%2Fworkflows%2Fcreate-from-template.md -->","isInternal":false,"tokens":752,"sizeBytes":3220},{"name":"debugging-mindset.md","path":"src/resources/skills/debug-like-expert/references/debugging-mindset.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/debug-like-expert/references/debugging-mindset.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2Freferences%2Fdebugging-mindset.md -->","isInternal":false,"tokens":2008,"sizeBytes":8868},{"name":"hypothesis-testing.md","path":"src/resources/skills/debug-like-expert/references/hypothesis-testing.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/debug-like-expert/references/hypothesis-testing.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2Freferences%2Fhypothesis-testing.md -->","isInternal":false,"tokens":2870,"sizeBytes":12131},{"name":"investigation-techniques.md","path":"src/resources/skills/debug-like-expert/references/investigation-techniques.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/debug-like-expert/references/investigation-techniques.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2Freferences%2Finvestigation-techniques.md -->","isInternal":false,"tokens":2383,"sizeBytes":9909},{"name":"verification-patterns.md","path":"src/resources/skills/debug-like-expert/references/verification-patterns.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/debug-like-expert/references/verification-patterns.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2Freferences%2Fverification-patterns.md -->","isInternal":false,"tokens":2692,"sizeBytes":11204},{"name":"when-to-research.md","path":"src/resources/skills/debug-like-expert/references/when-to-research.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/debug-like-expert/references/when-to-research.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2Freferences%2Fwhen-to-research.md -->","isInternal":false,"tokens":2380,"sizeBytes":10478},{"name":"SKILL.md","path":"src/resources/skills/debug-like-expert/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/debug-like-expert/SKILL.md","title":"debug-like-expert","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdebug-like-expert%2FSKILL.md -->","frontmatter":{"name":"debug-like-expert","description":"Deep analysis debugging mode for complex issues. Activates methodical investigation protocol with evidence gathering, hypothesis testing, and rigorous verification. Use when standard troubleshooting fails or when issues require systematic root cause analysis."},"isInternal":false,"tokens":1770,"sizeBytes":8576},{"name":"SKILL.md","path":"src/resources/skills/decompose-into-slices/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/decompose-into-slices/SKILL.md","title":"decompose-into-slices","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdecompose-into-slices%2FSKILL.md -->","frontmatter":{"name":"decompose-into-slices","description":"Break a plan or milestone brief into independently-grabbable vertical slices (tracer bullets). Produces slices in `M###-ROADMAP.md` by default, or GitHub issues only with explicit user confirmation. Use when asked to \"break this into slices\", \"decompose the plan\", \"vertical slices\", \"break into issues\", or when a plan is ready but needs task-level decomposition. Prefers many thin slices over few thick ones; marks dependency order explicitly."},"isInternal":false,"tokens":1783,"sizeBytes":7541},{"name":"SKILL.md","path":"src/resources/skills/dependency-upgrade/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/dependency-upgrade/SKILL.md","title":"dependency-upgrade","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdependency-upgrade%2FSKILL.md -->","frontmatter":{"name":"dependency-upgrade","description":"Plan, batch, and verify dependency upgrades safely. Triages outdated packages into risk tiers, upgrades in order (dev/minor/patch first, runtime majors last), verifies each batch before moving on, and produces an auditable commit sequence. Use when asked to \"upgrade deps\", \"bump packages\", \"update node_modules\", \"fix vulnerabilities\", \"upgrade React/Node/TypeScript\", or after `/gsd start dep-upgrade`. Complements the dep-upgrade workflow template with execution-level rigor."},"isInternal":false,"tokens":1972,"sizeBytes":7798},{"name":"SKILL.md","path":"src/resources/skills/design-an-interface/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/design-an-interface/SKILL.md","title":"design-an-interface","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fdesign-an-interface%2FSKILL.md -->","frontmatter":{"name":"design-an-interface","description":"Produce 3+ radically different designs for a module, API, or interface, compare them in prose, and synthesize a recommendation. Use when asked to \"design an interface\", \"shape this API\", \"design it twice\", \"explore module boundaries\", or when planning a new deep module and the first idea is unlikely to be the best. Based on \"Design It Twice\" from A Philosophy of Software Design — the value is the contrast, not the first draft."},"isInternal":false,"tokens":1217,"sizeBytes":5550},{"name":"SKILL.md","path":"src/resources/skills/forensics/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/forensics/SKILL.md","title":"forensics","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fforensics%2FSKILL.md -->","frontmatter":{"name":"forensics","description":"Post-mortem a failed GSD auto-mode run. Traces from symptom to root cause using `.gsd/activity/*.jsonl`, `.gsd/journal/YYYY-MM-DD.jsonl`, `.gsd/metrics.json`, and `.gsd/auto.lock`. Produces a filing-ready bug report with file:line references and a concrete fix suggestion. Use when asked to \"forensics\", \"post-mortem\", \"why did auto-mode fail\", \"trace the stuck loop\", \"debug the crash\", after `/gsd forensics` is invoked, or when a session ended in an unexpected terminal state. Reads existing artifacts — does NOT re-run anything."},"isInternal":false,"tokens":2067,"sizeBytes":8213},{"name":"SKILL.md","path":"src/resources/skills/frontend-design/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/frontend-design/SKILL.md","title":"frontend-design","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Ffrontend-design%2FSKILL.md -->","frontmatter":{"name":"frontend-design","description":"Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.","license":"Complete terms in LICENSE.txt"},"isInternal":false,"tokens":858,"sizeBytes":4443},{"name":"issue-stories.md","path":"src/resources/skills/github-workflows/references/gh/references/issue-stories.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/github-workflows/references/gh/references/issue-stories.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2Freferences%2Fgh%2Freferences%2Fissue-stories.md -->","isInternal":false,"tokens":1473,"sizeBytes":5597},{"name":"labels.md","path":"src/resources/skills/github-workflows/references/gh/references/labels.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/github-workflows/references/gh/references/labels.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2Freferences%2Fgh%2Freferences%2Flabels.md -->","isInternal":false,"tokens":1435,"sizeBytes":5131},{"name":"milestones.md","path":"src/resources/skills/github-workflows/references/gh/references/milestones.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/github-workflows/references/gh/references/milestones.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2Freferences%2Fgh%2Freferences%2Fmilestones.md -->","isInternal":false,"tokens":1171,"sizeBytes":4190},{"name":"projects-v2.md","path":"src/resources/skills/github-workflows/references/gh/references/projects-v2.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/github-workflows/references/gh/references/projects-v2.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2Freferences%2Fgh%2Freferences%2Fprojects-v2.md -->","isInternal":false,"tokens":1184,"sizeBytes":4465},{"name":"SKILL.md","path":"src/resources/skills/github-workflows/references/gh/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/github-workflows/references/gh/SKILL.md","title":"gh","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2Freferences%2Fgh%2FSKILL.md -->","frontmatter":{"name":"gh","description":"Install and configure the GitHub CLI (gh) for AI agent environments where gh may not be pre-installed and git remotes use local proxies instead of github.com. Provides auto-install script with SHA256 verification and GITHUB_TOKEN auth with anonymous fallback. Use when gh command not found, shutil.which(\"gh\") returns None, need GitHub API access (issues, PRs, releases, workflow runs), or repository operations fail with \"failed to determine base repo\" error. Documents required -R flag for all gh commands in proxy environments. Includes project management: GitHub Projects V2 (gh project), milestones (REST API), issue stories (lifecycle and templates), and label taxonomy management."},"isInternal":false,"tokens":2192,"sizeBytes":7983},{"name":"SKILL.md","path":"src/resources/skills/github-workflows/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/github-workflows/SKILL.md","title":"github-workflows","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgithub-workflows%2FSKILL.md -->","frontmatter":{"name":"github-workflows","description":"Work with GitHub Actions CI/CD workflows - read live syntax, monitor runs, and debug failures. Use when writing, running, or debugging GitHub Actions workflows."},"isInternal":false,"tokens":641,"sizeBytes":2600},{"name":"SKILL.md","path":"src/resources/skills/grill-me/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/grill-me/SKILL.md","title":"grill-me","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fgrill-me%2FSKILL.md -->","frontmatter":{"name":"grill-me","description":"Relentless sequential interview that stress-tests a plan or design until every decision branch is resolved. Use when the user wants to \"grill me\", \"stress-test the plan\", \"interrogate my design\", \"resolve the decision tree\", or whenever a plan feels hand-wavy, under-specified, or carries hidden coupling that planning phases must surface before execution. Pairs with the discuss phase and blocks execution until alignment is reached."},"isInternal":false,"tokens":1168,"sizeBytes":5158},{"name":"SKILL.md","path":"src/resources/skills/handoff/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/handoff/SKILL.md","title":"handoff","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fhandoff%2FSKILL.md -->","frontmatter":{"name":"handoff","description":"Prepare a clean cross-session handoff so the next agent (or you tomorrow) can pick up exactly where you left off. Writes a focused `continue.md` in the active slice directory and ensures `STATE.md` + summary artifacts are current. Use when asked to \"hand off\", \"prepare handoff\", \"pause work\", \"bookmark this\", \"I'll come back to this later\", before running out of context budget, or at the end of a long session with unfinished work. Closes the v1 `/gsd-pause-work` parity gap."},"isInternal":false,"tokens":1518,"sizeBytes":6099},{"name":"SKILL.md","path":"src/resources/skills/lint/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/lint/SKILL.md","title":"lint","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Flint%2FSKILL.md -->","frontmatter":{"name":"lint","description":"Lint and format code. Auto-detects ESLint, Biome, Prettier, or language-native formatters and runs them with auto-fix. Reports remaining issues with actionable suggestions."},"isInternal":false,"tokens":1801,"sizeBytes":6863},{"name":"animations.md","path":"src/resources/skills/make-interfaces-feel-better/animations.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/make-interfaces-feel-better/animations.md","title":"Make-interfaces-feel-better Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fmake-interfaces-feel-better%2Fanimations.md -->","isInternal":false,"tokens":2844,"sizeBytes":11092},{"name":"performance.md","path":"src/resources/skills/make-interfaces-feel-better/performance.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/make-interfaces-feel-better/performance.md","title":"Make-interfaces-feel-better Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fmake-interfaces-feel-better%2Fperformance.md -->","isInternal":false,"tokens":644,"sizeBytes":2884},{"name":"SKILL.md","path":"src/resources/skills/make-interfaces-feel-better/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/make-interfaces-feel-better/SKILL.md","title":"make-interfaces-feel-better","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fmake-interfaces-feel-better%2FSKILL.md -->","frontmatter":{"name":"make-interfaces-feel-better","description":"Design engineering principles for making interfaces feel polished. Use when building UI components, reviewing frontend code, implementing animations, hover states, shadows, borders, typography, micro-interactions, enter/exit animations, or any visual detail work. Triggers on UI polish, design details, \"make it feel better\", \"feels off\", stagger animations, border radius, optical alignment, font smoothing, tabular numbers, image outlines, box shadows."},"isInternal":false,"tokens":1417,"sizeBytes":6133},{"name":"surfaces.md","path":"src/resources/skills/make-interfaces-feel-better/surfaces.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/make-interfaces-feel-better/surfaces.md","title":"Make-interfaces-feel-better Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fmake-interfaces-feel-better%2Fsurfaces.md -->","isInternal":false,"tokens":1757,"sizeBytes":6586},{"name":"typography.md","path":"src/resources/skills/make-interfaces-feel-better/typography.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/make-interfaces-feel-better/typography.md","title":"Make-interfaces-feel-better Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fmake-interfaces-feel-better%2Ftypography.md -->","isInternal":false,"tokens":776,"sizeBytes":3180},{"name":"SKILL.md","path":"src/resources/skills/observability/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/observability/SKILL.md","title":"observability","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fobservability%2FSKILL.md -->","frontmatter":{"name":"observability","description":"Add agent-first observability to code — structured logs, health endpoints, failure-state persistence, and explicit failure modes — so the next agent hitting a problem at 3am has the signals it needs to diagnose. Use when asked to \"add logging\", \"add observability\", \"add metrics\", \"debug later\", \"make this observable\", or when building/refactoring a subsystem that will run unattended (auto-mode engine, background jobs, servers, watchers). Operationalizes VISION.md's \"agent-first observability\" principle."},"isInternal":false,"tokens":1900,"sizeBytes":8152},{"name":"metadata.json","path":"src/resources/skills/react-best-practices/metadata.json","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/metadata.json","title":"React-best-practices Skill","category":"anthropic-skill","format":"json","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Fmetadata.json -->","frontmatter":{"version":"1.0.0","organization":"Vercel Engineering","date":"January 2026","abstract":"Comprehensive performance optimization guide for React and Next.js applications, designed for AI agents and LLMs. Contains 40+ rules across 8 categories, prioritized by impact from critical (eliminating waterfalls, reducing bundle size) to incremental (advanced patterns). Each rule includes detailed explanations, real-world examples comparing incorrect vs. correct implementations, and specific impact metrics to guide automated refactoring and code generation.","references":["https://react.dev","https://nextjs.org","https://swr.vercel.app","https://github.com/shuding/better-all","https://github.com/isaacs/node-lru-cache","https://vercel.com/blog/how-we-optimized-package-imports-in-next-js","https://vercel.com/blog/how-we-made-the-vercel-dashboard-twice-as-fast"]},"isInternal":false,"tokens":217,"sizeBytes":921},{"name":"README.md","path":"src/resources/skills/react-best-practices/README.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/README.md","title":"React-best-practices Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2FREADME.md -->","isInternal":false,"tokens":848,"sizeBytes":3360},{"name":"_sections.md","path":"src/resources/skills/react-best-practices/rules/_sections.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/_sections.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2F_sections.md -->","isInternal":false,"tokens":318,"sizeBytes":1554},{"name":"_template.md","path":"src/resources/skills/react-best-practices/rules/_template.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/_template.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2F_template.md -->","frontmatter":{"title":"Rule Title Here","impact":"MEDIUM","impactDescription":"Optional description of impact (e.g., \"20-50% improvement\")","tags":"tag1, tag2"},"isInternal":false,"tokens":143,"sizeBytes":631},{"name":"advanced-event-handler-refs.md","path":"src/resources/skills/react-best-practices/rules/advanced-event-handler-refs.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/advanced-event-handler-refs.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fadvanced-event-handler-refs.md -->","frontmatter":{"title":"Store Event Handlers in Refs","impact":"LOW","impactDescription":"stable subscriptions","tags":"advanced, hooks, refs, event-handlers, optimization"},"isInternal":false,"tokens":337,"sizeBytes":1483},{"name":"advanced-init-once.md","path":"src/resources/skills/react-best-practices/rules/advanced-init-once.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/advanced-init-once.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fadvanced-init-once.md -->","frontmatter":{"title":"Initialize App Once, Not Per Mount","impact":"LOW-MEDIUM","impactDescription":"avoids duplicate init in development","tags":"initialization, useEffect, app-startup, side-effects"},"isInternal":false,"tokens":230,"sizeBytes":958},{"name":"advanced-use-latest.md","path":"src/resources/skills/react-best-practices/rules/advanced-use-latest.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/advanced-use-latest.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fadvanced-use-latest.md -->","frontmatter":{"title":"useEffectEvent for Stable Callback Refs","impact":"LOW","impactDescription":"prevents effect re-runs","tags":"advanced, hooks, useEffectEvent, refs, optimization"},"isInternal":false,"tokens":254,"sizeBytes":1072},{"name":"async-api-routes.md","path":"src/resources/skills/react-best-practices/rules/async-api-routes.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/async-api-routes.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fasync-api-routes.md -->","frontmatter":{"title":"Prevent Waterfall Chains in API Routes","impact":"CRITICAL","impactDescription":"2-10× improvement","tags":"api-routes, server-actions, waterfalls, parallelization"},"isInternal":false,"tokens":241,"sizeBytes":1125},{"name":"async-defer-await.md","path":"src/resources/skills/react-best-practices/rules/async-defer-await.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/async-defer-await.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fasync-defer-await.md -->","frontmatter":{"title":"Defer Await Until Needed","impact":"HIGH","impactDescription":"avoids blocking unused code paths","tags":"async, await, conditional, optimization"},"isInternal":false,"tokens":437,"sizeBytes":2028},{"name":"async-dependencies.md","path":"src/resources/skills/react-best-practices/rules/async-dependencies.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/async-dependencies.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fasync-dependencies.md -->","frontmatter":{"title":"Dependency-Based Parallelization","impact":"CRITICAL","impactDescription":"2-10× improvement","tags":"async, parallelization, dependencies, better-all"},"isInternal":false,"tokens":291,"sizeBytes":1293},{"name":"async-parallel.md","path":"src/resources/skills/react-best-practices/rules/async-parallel.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/async-parallel.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fasync-parallel.md -->","frontmatter":{"title":"Promise.all() for Independent Operations","impact":"CRITICAL","impactDescription":"2-10× improvement","tags":"async, parallelization, promises, waterfalls"},"isInternal":false,"tokens":144,"sizeBytes":654},{"name":"async-suspense-boundaries.md","path":"src/resources/skills/react-best-practices/rules/async-suspense-boundaries.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/async-suspense-boundaries.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fasync-suspense-boundaries.md -->","frontmatter":{"title":"Strategic Suspense Boundaries","impact":"HIGH","impactDescription":"faster initial paint","tags":"async, suspense, streaming, layout-shift"},"isInternal":false,"tokens":591,"sizeBytes":2510},{"name":"bundle-barrel-imports.md","path":"src/resources/skills/react-best-practices/rules/bundle-barrel-imports.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/bundle-barrel-imports.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fbundle-barrel-imports.md -->","frontmatter":{"title":"Avoid Barrel File Imports","impact":"CRITICAL","impactDescription":"200-800ms import cost, slow builds","tags":"bundle, imports, tree-shaking, barrel-files, performance"},"isInternal":false,"tokens":595,"sizeBytes":2370},{"name":"bundle-conditional.md","path":"src/resources/skills/react-best-practices/rules/bundle-conditional.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/bundle-conditional.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fbundle-conditional.md -->","frontmatter":{"title":"Conditional Module Loading","impact":"HIGH","impactDescription":"loads large data only when needed","tags":"bundle, conditional-loading, lazy-loading"},"isInternal":false,"tokens":213,"sizeBytes":949},{"name":"bundle-defer-third-party.md","path":"src/resources/skills/react-best-practices/rules/bundle-defer-third-party.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/bundle-defer-third-party.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fbundle-defer-third-party.md -->","frontmatter":{"title":"Defer Non-Critical Third-Party Libraries","impact":"MEDIUM","impactDescription":"loads after hydration","tags":"bundle, third-party, analytics, defer"},"isInternal":false,"tokens":221,"sizeBytes":920},{"name":"bundle-dynamic-imports.md","path":"src/resources/skills/react-best-practices/rules/bundle-dynamic-imports.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/bundle-dynamic-imports.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fbundle-dynamic-imports.md -->","frontmatter":{"title":"Dynamic Imports for Heavy Components","impact":"CRITICAL","impactDescription":"directly affects TTI and LCP","tags":"bundle, dynamic-import, code-splitting, next-dynamic"},"isInternal":false,"tokens":197,"sizeBytes":791},{"name":"bundle-preload.md","path":"src/resources/skills/react-best-practices/rules/bundle-preload.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/bundle-preload.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fbundle-preload.md -->","frontmatter":{"title":"Preload Based on User Intent","impact":"MEDIUM","impactDescription":"reduces perceived latency","tags":"bundle, preload, user-intent, hover"},"isInternal":false,"tokens":267,"sizeBytes":1149},{"name":"client-event-listeners.md","path":"src/resources/skills/react-best-practices/rules/client-event-listeners.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/client-event-listeners.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fclient-event-listeners.md -->","frontmatter":{"title":"Deduplicate Global Event Listeners","impact":"LOW","impactDescription":"single listener for N components","tags":"client, swr, event-listeners, subscription"},"isInternal":false,"tokens":466,"sizeBytes":1969},{"name":"client-localstorage-schema.md","path":"src/resources/skills/react-best-practices/rules/client-localstorage-schema.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/client-localstorage-schema.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fclient-localstorage-schema.md -->","frontmatter":{"title":"Version and Minimize localStorage Data","impact":"MEDIUM","impactDescription":"prevents schema conflicts, reduces storage size","tags":"client, localStorage, storage, versioning, data-minimization"},"isInternal":false,"tokens":437,"sizeBytes":1950},{"name":"client-passive-event-listeners.md","path":"src/resources/skills/react-best-practices/rules/client-passive-event-listeners.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/client-passive-event-listeners.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fclient-passive-event-listeners.md -->","frontmatter":{"title":"Use Passive Event Listeners for Scrolling Performance","impact":"MEDIUM","impactDescription":"eliminates scroll delay caused by event listeners","tags":"client, event-listeners, scrolling, performance, touch, wheel"},"isInternal":false,"tokens":361,"sizeBytes":1644},{"name":"client-swr-dedup.md","path":"src/resources/skills/react-best-practices/rules/client-swr-dedup.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/client-swr-dedup.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fclient-swr-dedup.md -->","frontmatter":{"title":"Use SWR for Automatic Deduplication","impact":"MEDIUM-HIGH","impactDescription":"automatic deduplication","tags":"client, swr, deduplication, data-fetching"},"isInternal":false,"tokens":308,"sizeBytes":1159},{"name":"js-batch-dom-css.md","path":"src/resources/skills/react-best-practices/rules/js-batch-dom-css.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/js-batch-dom-css.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-batch-dom-css.md -->","frontmatter":{"title":"Avoid Layout Thrashing","impact":"MEDIUM","impactDescription":"prevents forced synchronous layouts and reduces performance bottlenecks","tags":"javascript, dom, css, performance, reflow, layout-thrashing"},"isInternal":false,"tokens":757,"sizeBytes":3266},{"name":"js-cache-function-results.md","path":"src/resources/skills/react-best-practices/rules/js-cache-function-results.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/js-cache-function-results.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-cache-function-results.md -->","frontmatter":{"title":"Cache Repeated Function Calls","impact":"MEDIUM","impactDescription":"avoid redundant computation","tags":"javascript, cache, memoization, performance"},"isInternal":false,"tokens":448,"sizeBytes":1949},{"name":"js-cache-property-access.md","path":"src/resources/skills/react-best-practices/rules/js-cache-property-access.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/js-cache-property-access.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-cache-property-access.md -->","frontmatter":{"title":"Cache Property Access in Loops","impact":"LOW-MEDIUM","impactDescription":"reduces lookups","tags":"javascript, loops, optimization, caching"},"isInternal":false,"tokens":138,"sizeBytes":532},{"name":"js-cache-storage.md","path":"src/resources/skills/react-best-practices/rules/js-cache-storage.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/js-cache-storage.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-cache-storage.md -->","frontmatter":{"title":"Cache Storage API Calls","impact":"LOW-MEDIUM","impactDescription":"reduces expensive I/O","tags":"javascript, localStorage, storage, caching, performance"},"isInternal":false,"tokens":377,"sizeBytes":1651},{"name":"js-combine-iterations.md","path":"src/resources/skills/react-best-practices/rules/js-combine-iterations.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/js-combine-iterations.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-combine-iterations.md -->","frontmatter":{"title":"Combine Multiple Array Iterations","impact":"LOW-MEDIUM","impactDescription":"reduces iterations","tags":"javascript, arrays, loops, performance"},"isInternal":false,"tokens":176,"sizeBytes":753},{"name":"js-early-exit.md","path":"src/resources/skills/react-best-practices/rules/js-early-exit.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/js-early-exit.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-early-exit.md -->","frontmatter":{"title":"Early Return from Functions","impact":"LOW-MEDIUM","impactDescription":"avoids unnecessary computation","tags":"javascript, functions, optimization, early-return"},"isInternal":false,"tokens":266,"sizeBytes":1133},{"name":"js-hoist-regexp.md","path":"src/resources/skills/react-best-practices/rules/js-hoist-regexp.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/js-hoist-regexp.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-hoist-regexp.md -->","frontmatter":{"title":"Hoist RegExp Creation","impact":"LOW-MEDIUM","impactDescription":"avoids recreation","tags":"javascript, regexp, optimization, memoization"},"isInternal":false,"tokens":283,"sizeBytes":1028},{"name":"js-index-maps.md","path":"src/resources/skills/react-best-practices/rules/js-index-maps.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/js-index-maps.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-index-maps.md -->","frontmatter":{"title":"Build Index Maps for Repeated Lookups","impact":"LOW-MEDIUM","impactDescription":"1M ops to 2K ops","tags":"javascript, map, indexing, optimization, performance"},"isInternal":false,"tokens":229,"sizeBytes":837},{"name":"js-length-check-first.md","path":"src/resources/skills/react-best-practices/rules/js-length-check-first.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/js-length-check-first.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-length-check-first.md -->","frontmatter":{"title":"Early Length Check for Array Comparisons","impact":"MEDIUM-HIGH","impactDescription":"avoids expensive operations when lengths differ","tags":"javascript, arrays, performance, optimization, comparison"},"isInternal":false,"tokens":373,"sizeBytes":1747},{"name":"js-min-max-loop.md","path":"src/resources/skills/react-best-practices/rules/js-min-max-loop.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/js-min-max-loop.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-min-max-loop.md -->","frontmatter":{"title":"Use Loop for Min/Max Instead of Sort","impact":"LOW","impactDescription":"O(n) instead of O(n log n)","tags":"javascript, arrays, performance, sorting, algorithms"},"isInternal":false,"tokens":602,"sizeBytes":2290},{"name":"js-set-map-lookups.md","path":"src/resources/skills/react-best-practices/rules/js-set-map-lookups.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/js-set-map-lookups.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-set-map-lookups.md -->","frontmatter":{"title":"Use Set/Map for O(1) Lookups","impact":"LOW-MEDIUM","impactDescription":"O(n) to O(1)","tags":"javascript, set, map, data-structures, performance"},"isInternal":false,"tokens":154,"sizeBytes":532},{"name":"js-tosorted-immutable.md","path":"src/resources/skills/react-best-practices/rules/js-tosorted-immutable.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/js-tosorted-immutable.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fjs-tosorted-immutable.md -->","frontmatter":{"title":"Use toSorted() Instead of sort() for Immutability","impact":"MEDIUM-HIGH","impactDescription":"prevents mutation bugs in React state","tags":"javascript, arrays, immutability, react, state, mutation"},"isInternal":false,"tokens":436,"sizeBytes":1782},{"name":"rendering-activity.md","path":"src/resources/skills/react-best-practices/rules/rendering-activity.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rendering-activity.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-activity.md -->","frontmatter":{"title":"Use Activity Component for Show/Hide","impact":"MEDIUM","impactDescription":"preserves state/DOM","tags":"rendering, activity, visibility, state-preservation"},"isInternal":false,"tokens":131,"sizeBytes":564},{"name":"rendering-animate-svg-wrapper.md","path":"src/resources/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-animate-svg-wrapper.md -->","frontmatter":{"title":"Animate SVG Wrapper Instead of SVG Element","impact":"LOW","impactDescription":"enables hardware acceleration","tags":"rendering, svg, css, animation, performance"},"isInternal":false,"tokens":291,"sizeBytes":1185},{"name":"rendering-conditional-render.md","path":"src/resources/skills/react-best-practices/rules/rendering-conditional-render.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rendering-conditional-render.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-conditional-render.md -->","frontmatter":{"title":"Use Explicit Conditional Rendering","impact":"LOW","impactDescription":"prevents rendering 0 or NaN","tags":"rendering, conditional, jsx, falsy-values"},"isInternal":false,"tokens":273,"sizeBytes":980},{"name":"rendering-content-visibility.md","path":"src/resources/skills/react-best-practices/rules/rendering-content-visibility.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rendering-content-visibility.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-content-visibility.md -->","frontmatter":{"title":"CSS content-visibility for Long Lists","impact":"HIGH","impactDescription":"faster initial render","tags":"rendering, css, content-visibility, long-lists"},"isInternal":false,"tokens":203,"sizeBytes":815},{"name":"rendering-hoist-jsx.md","path":"src/resources/skills/react-best-practices/rules/rendering-hoist-jsx.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rendering-hoist-jsx.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-hoist-jsx.md -->","frontmatter":{"title":"Hoist Static JSX Elements","impact":"LOW","impactDescription":"avoids re-creation","tags":"rendering, jsx, static, optimization"},"isInternal":false,"tokens":244,"sizeBytes":1039},{"name":"rendering-hydration-no-flicker.md","path":"src/resources/skills/react-best-practices/rules/rendering-hydration-no-flicker.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rendering-hydration-no-flicker.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-hydration-no-flicker.md -->","frontmatter":{"title":"Prevent Hydration Mismatch Without Flickering","impact":"MEDIUM","impactDescription":"avoids visual flicker and hydration errors","tags":"rendering, ssr, hydration, localStorage, flicker"},"isInternal":false,"tokens":490,"sizeBytes":2308},{"name":"rendering-hydration-suppress-warning.md","path":"src/resources/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-hydration-suppress-warning.md -->","frontmatter":{"title":"Suppress Expected Hydration Mismatches","impact":"LOW-MEDIUM","impactDescription":"avoids noisy hydration warnings for known differences","tags":"rendering, hydration, ssr, nextjs"},"isInternal":false,"tokens":197,"sizeBytes":872},{"name":"rendering-svg-precision.md","path":"src/resources/skills/react-best-practices/rules/rendering-svg-precision.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rendering-svg-precision.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-svg-precision.md -->","frontmatter":{"title":"Optimize SVG Precision","impact":"LOW","impactDescription":"reduces file size","tags":"rendering, svg, optimization, svgo"},"isInternal":false,"tokens":167,"sizeBytes":588},{"name":"rendering-usetransition-loading.md","path":"src/resources/skills/react-best-practices/rules/rendering-usetransition-loading.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rendering-usetransition-loading.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frendering-usetransition-loading.md -->","frontmatter":{"title":"Use useTransition Over Manual Loading States","impact":"LOW","impactDescription":"reduces re-renders and improves code clarity","tags":"rendering, transitions, useTransition, loading, state"},"isInternal":false,"tokens":457,"sizeBytes":2074},{"name":"rerender-defer-reads.md","path":"src/resources/skills/react-best-practices/rules/rerender-defer-reads.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rerender-defer-reads.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-defer-reads.md -->","frontmatter":{"title":"Defer State Reads to Usage Point","impact":"MEDIUM","impactDescription":"avoids unnecessary subscriptions","tags":"rerender, searchParams, localStorage, optimization"},"isInternal":false,"tokens":231,"sizeBytes":973},{"name":"rerender-dependencies.md","path":"src/resources/skills/react-best-practices/rules/rerender-dependencies.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rerender-dependencies.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-dependencies.md -->","frontmatter":{"title":"Narrow Effect Dependencies","impact":"LOW","impactDescription":"minimizes effect re-runs","tags":"rerender, useEffect, dependencies, optimization"},"isInternal":false,"tokens":214,"sizeBytes":824},{"name":"rerender-derived-state-no-effect.md","path":"src/resources/skills/react-best-practices/rules/rerender-derived-state-no-effect.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rerender-derived-state-no-effect.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-derived-state-no-effect.md -->","frontmatter":{"title":"Calculate Derived State During Rendering","impact":"MEDIUM","impactDescription":"avoids redundant renders and state drift","tags":"rerender, derived-state, useEffect, state"},"isInternal":false,"tokens":283,"sizeBytes":1201},{"name":"rerender-derived-state.md","path":"src/resources/skills/react-best-practices/rules/rerender-derived-state.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rerender-derived-state.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-derived-state.md -->","frontmatter":{"title":"Subscribe to Derived State","impact":"MEDIUM","impactDescription":"reduces re-render frequency","tags":"rerender, derived-state, media-query, optimization"},"isInternal":false,"tokens":175,"sizeBytes":728},{"name":"rerender-functional-setstate.md","path":"src/resources/skills/react-best-practices/rules/rerender-functional-setstate.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rerender-functional-setstate.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-functional-setstate.md -->","frontmatter":{"title":"Use Functional setState Updates","impact":"MEDIUM","impactDescription":"prevents stale closures and unnecessary callback recreations","tags":"react, hooks, useState, useCallback, callbacks, closures"},"isInternal":false,"tokens":654,"sizeBytes":2968},{"name":"rerender-lazy-state-init.md","path":"src/resources/skills/react-best-practices/rules/rerender-lazy-state-init.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rerender-lazy-state-init.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-lazy-state-init.md -->","frontmatter":{"title":"Use Lazy State Initialization","impact":"MEDIUM","impactDescription":"wasted computation on every render","tags":"react, hooks, useState, performance, initialization"},"isInternal":false,"tokens":438,"sizeBytes":2016},{"name":"rerender-memo-with-default-value.md","path":"src/resources/skills/react-best-practices/rules/rerender-memo-with-default-value.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rerender-memo-with-default-value.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-memo-with-default-value.md -->","frontmatter":{"title":"Extract Default Non-primitive Parameter Value from Memoized Component to Constant","impact":"MEDIUM","impactDescription":"restores memoization by using a constant for default value","tags":"rerender, memo, optimization"},"isInternal":false,"tokens":248,"sizeBytes":1173},{"name":"rerender-memo.md","path":"src/resources/skills/react-best-practices/rules/rerender-memo.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rerender-memo.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-memo.md -->","frontmatter":{"title":"Extract to Memoized Components","impact":"MEDIUM","impactDescription":"enables early returns","tags":"rerender, memo, useMemo, optimization"},"isInternal":false,"tokens":278,"sizeBytes":1148},{"name":"rerender-move-effect-to-event.md","path":"src/resources/skills/react-best-practices/rules/rerender-move-effect-to-event.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rerender-move-effect-to-event.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-move-effect-to-event.md -->","frontmatter":{"title":"Put Interaction Logic in Event Handlers","impact":"MEDIUM","impactDescription":"avoids effect re-runs and duplicate side effects","tags":"rerender, useEffect, events, side-effects, dependencies"},"isInternal":false,"tokens":285,"sizeBytes":1268},{"name":"rerender-simple-expression-in-memo.md","path":"src/resources/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-simple-expression-in-memo.md -->","frontmatter":{"title":"Do not wrap a simple expression with a primitive result type in useMemo","impact":"LOW-MEDIUM","impactDescription":"wasted computation on every render","tags":"rerender, useMemo, optimization"},"isInternal":false,"tokens":217,"sizeBytes":1018},{"name":"rerender-transitions.md","path":"src/resources/skills/react-best-practices/rules/rerender-transitions.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rerender-transitions.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-transitions.md -->","frontmatter":{"title":"Use Transitions for Non-Urgent Updates","impact":"MEDIUM","impactDescription":"maintains UI responsiveness","tags":"rerender, transitions, startTransition, performance"},"isInternal":false,"tokens":241,"sizeBytes":1055},{"name":"rerender-use-ref-transient-values.md","path":"src/resources/skills/react-best-practices/rules/rerender-use-ref-transient-values.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/rerender-use-ref-transient-values.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Frerender-use-ref-transient-values.md -->","frontmatter":{"title":"Use useRef for Transient Values","impact":"MEDIUM","impactDescription":"avoids unnecessary re-renders on frequent updates","tags":"rerender, useref, state, performance"},"isInternal":false,"tokens":436,"sizeBytes":1742},{"name":"server-after-nonblocking.md","path":"src/resources/skills/react-best-practices/rules/server-after-nonblocking.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/server-after-nonblocking.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-after-nonblocking.md -->","frontmatter":{"title":"Use after() for Non-Blocking Operations","impact":"MEDIUM","impactDescription":"faster response times","tags":"server, async, logging, analytics, side-effects"},"isInternal":false,"tokens":458,"sizeBytes":2012},{"name":"server-auth-actions.md","path":"src/resources/skills/react-best-practices/rules/server-auth-actions.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/server-auth-actions.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-auth-actions.md -->","frontmatter":{"title":"Authenticate Server Actions Like API Routes","impact":"CRITICAL","impactDescription":"prevents unauthorized access to server mutations","tags":"server, server-actions, authentication, security, authorization"},"isInternal":false,"tokens":585,"sizeBytes":2649},{"name":"server-cache-lru.md","path":"src/resources/skills/react-best-practices/rules/server-cache-lru.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/server-cache-lru.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-cache-lru.md -->","frontmatter":{"title":"Cross-Request LRU Caching","impact":"HIGH","impactDescription":"caches across requests","tags":"server, cache, lru, cross-request"},"isInternal":false,"tokens":326,"sizeBytes":1353},{"name":"server-cache-react.md","path":"src/resources/skills/react-best-practices/rules/server-cache-react.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/server-cache-react.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-cache-react.md -->","frontmatter":{"title":"Per-Request Deduplication with React.cache()","impact":"MEDIUM","impactDescription":"deduplicates within request","tags":"server, cache, react-cache, deduplication"},"isInternal":false,"tokens":513,"sizeBytes":2228},{"name":"server-dedup-props.md","path":"src/resources/skills/react-best-practices/rules/server-dedup-props.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/server-dedup-props.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-dedup-props.md -->","frontmatter":{"title":"Avoid Duplicate Serialization in RSC Props","impact":"LOW","impactDescription":"reduces network payload by avoiding duplicate serialization","tags":"server, rsc, serialization, props, client-components"},"isInternal":false,"tokens":499,"sizeBytes":2060},{"name":"server-parallel-fetching.md","path":"src/resources/skills/react-best-practices/rules/server-parallel-fetching.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/server-parallel-fetching.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-parallel-fetching.md -->","frontmatter":{"title":"Parallel Data Fetching with Component Composition","impact":"CRITICAL","impactDescription":"eliminates server-side waterfalls","tags":"server, rsc, parallel-fetching, composition"},"isInternal":false,"tokens":365,"sizeBytes":1554},{"name":"server-serialization.md","path":"src/resources/skills/react-best-practices/rules/server-serialization.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/rules/server-serialization.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2Frules%2Fserver-serialization.md -->","frontmatter":{"title":"Minimize Serialization at RSC Boundaries","impact":"HIGH","impactDescription":"reduces data transfer size","tags":"server, rsc, serialization, props"},"isInternal":false,"tokens":242,"sizeBytes":996},{"name":"SKILL.md","path":"src/resources/skills/react-best-practices/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/react-best-practices/SKILL.md","title":"react-best-practices","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freact-best-practices%2FSKILL.md -->","frontmatter":{"name":"react-best-practices","description":"React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.","license":"MIT","metadata":{"author":"vercel","version":"1.0.0"}},"isInternal":false,"tokens":1486,"sizeBytes":6158},{"name":"SKILL.md","path":"src/resources/skills/review/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/review/SKILL.md","title":"review","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Freview%2FSKILL.md -->","frontmatter":{"name":"review","description":"Review code changes for security, performance, bugs, and quality. Reviews staged changes, unstaged changes, specific commits, or PR-ready diffs."},"isInternal":false,"tokens":1881,"sizeBytes":8580},{"name":"SKILL.md","path":"src/resources/skills/security-review/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/security-review/SKILL.md","title":"security-review","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fsecurity-review%2FSKILL.md -->","frontmatter":{"name":"security-review","description":"Threat-model-driven security review of a change, feature, or subsystem. Runs a STRIDE-style pass (Spoofing, Tampering, Repudiation, Info disclosure, Denial of service, Elevation of privilege), examines the actual code, and produces a filing-ready report with severity, exploit scenario, and concrete remediation. Use when asked to \"security review\", \"threat model\", \"check for vulnerabilities\", \"audit this for security\", \"secure this\", or before shipping any change that touches auth, input handling, data access, or external surfaces."},"isInternal":false,"tokens":1810,"sizeBytes":7949},{"name":"SKILL.md","path":"src/resources/skills/spike-wrap-up/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/spike-wrap-up/SKILL.md","title":"spike-wrap-up","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fspike-wrap-up%2FSKILL.md -->","frontmatter":{"name":"spike-wrap-up","description":"Package findings from a completed spike into a durable, project-local skill that auto-loads on future similar work. Reads the most recent `.gsd/workflows/spikes/` directory, interviews the user briefly on what's reusable, then writes `.claude/skills/<name>/SKILL.md`. Use when asked to \"wrap up the spike\", \"package this as a skill\", \"make this reusable\", \"turn findings into a skill\", or at the end of the synthesize phase of `/gsd start spike`. Closes the parity gap with GSD v1's `/gsd-spike-wrap-up`."},"isInternal":false,"tokens":1669,"sizeBytes":6972},{"name":"SKILL.md","path":"src/resources/skills/tdd/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/tdd/SKILL.md","title":"tdd","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Ftdd%2FSKILL.md -->","frontmatter":{"name":"tdd","description":"Test-driven development with red-green-refactor loops built around vertical slices (tracer bullets), not horizontal layers. Use when asked to \"use TDD\", \"write test-first\", \"red-green-refactor\", \"build this with tests\", or whenever a feature has a clear observable contract and would benefit from tests that outlive refactors. Complements the bundled test and add-tests skills — use this for the discipline, use those for the mechanics."},"isInternal":false,"tokens":1466,"sizeBytes":6608},{"name":"SKILL.md","path":"src/resources/skills/test/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/test/SKILL.md","title":"test","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Ftest%2FSKILL.md -->","frontmatter":{"name":"test","description":"Generate or run tests. Auto-detects test framework, generates comprehensive tests for source files, or runs existing test suites with failure analysis."},"isInternal":false,"tokens":1746,"sizeBytes":7352},{"name":"_sections.md","path":"src/resources/skills/userinterface-wiki/rules/_sections.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/_sections.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2F_sections.md -->","isInternal":false,"tokens":681,"sizeBytes":3270},{"name":"_template.md","path":"src/resources/skills/userinterface-wiki/rules/_template.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/_template.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2F_template.md -->","frontmatter":{"title":"Rule Title Here","impact":"MEDIUM","impactDescription":"Optional description of impact","tags":"tag1, tag2"},"isInternal":false,"tokens":100,"sizeBytes":418},{"name":"a11y-reduced-motion-check.md","path":"src/resources/skills/userinterface-wiki/rules/a11y-reduced-motion-check.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/a11y-reduced-motion-check.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fa11y-reduced-motion-check.md -->","frontmatter":{"title":"Respect prefers-reduced-motion for Sound","impact":"HIGH","tags":"a11y, reduced-motion, sound"},"isInternal":false,"tokens":136,"sizeBytes":554},{"name":"a11y-toggle-setting.md","path":"src/resources/skills/userinterface-wiki/rules/a11y-toggle-setting.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/a11y-toggle-setting.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fa11y-toggle-setting.md -->","frontmatter":{"title":"Toggle Setting to Disable Sounds","impact":"HIGH","tags":"a11y, settings, toggle"},"isInternal":false,"tokens":120,"sizeBytes":508},{"name":"a11y-visual-equivalent.md","path":"src/resources/skills/userinterface-wiki/rules/a11y-visual-equivalent.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/a11y-visual-equivalent.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fa11y-visual-equivalent.md -->","frontmatter":{"title":"Visual Equivalent for Every Sound","impact":"HIGH","tags":"a11y, visual, sound"},"isInternal":false,"tokens":156,"sizeBytes":674},{"name":"a11y-volume-control.md","path":"src/resources/skills/userinterface-wiki/rules/a11y-volume-control.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/a11y-volume-control.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fa11y-volume-control.md -->","frontmatter":{"title":"Independent Volume Control","impact":"MEDIUM","tags":"a11y, volume, settings"},"isInternal":false,"tokens":104,"sizeBytes":438},{"name":"appropriate-confirmations-only.md","path":"src/resources/skills/userinterface-wiki/rules/appropriate-confirmations-only.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/appropriate-confirmations-only.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fappropriate-confirmations-only.md -->","frontmatter":{"title":"Sound for Confirmations","impact":"MEDIUM","tags":"appropriate, confirmation, payment"},"isInternal":false,"tokens":73,"sizeBytes":334},{"name":"appropriate-errors-warnings.md","path":"src/resources/skills/userinterface-wiki/rules/appropriate-errors-warnings.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/appropriate-errors-warnings.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fappropriate-errors-warnings.md -->","frontmatter":{"title":"Sound for Errors and Warnings","impact":"MEDIUM","tags":"appropriate, error, warning"},"isInternal":false,"tokens":74,"sizeBytes":320},{"name":"appropriate-no-decorative.md","path":"src/resources/skills/userinterface-wiki/rules/appropriate-no-decorative.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/appropriate-no-decorative.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fappropriate-no-decorative.md -->","frontmatter":{"title":"No Decorative Sound","impact":"MEDIUM","tags":"appropriate, decorative, hover"},"isInternal":false,"tokens":86,"sizeBytes":347},{"name":"appropriate-no-high-frequency.md","path":"src/resources/skills/userinterface-wiki/rules/appropriate-no-high-frequency.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/appropriate-no-high-frequency.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fappropriate-no-high-frequency.md -->","frontmatter":{"title":"No Sound on High-Frequency Interactions","impact":"HIGH","tags":"appropriate, frequency, typing"},"isInternal":false,"tokens":124,"sizeBytes":519},{"name":"appropriate-no-punishing.md","path":"src/resources/skills/userinterface-wiki/rules/appropriate-no-punishing.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/appropriate-no-punishing.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fappropriate-no-punishing.md -->","frontmatter":{"title":"Informative Not Punishing Sound","impact":"MEDIUM","tags":"appropriate, error, tone"},"isInternal":false,"tokens":119,"sizeBytes":478},{"name":"container-callback-ref.md","path":"src/resources/skills/userinterface-wiki/rules/container-callback-ref.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/container-callback-ref.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-callback-ref.md -->","frontmatter":{"title":"Use Callback Ref for Measurement","impact":"MEDIUM","tags":"container, ref, callback"},"isInternal":false,"tokens":163,"sizeBytes":701},{"name":"container-guard-initial-zero.md","path":"src/resources/skills/userinterface-wiki/rules/container-guard-initial-zero.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/container-guard-initial-zero.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-guard-initial-zero.md -->","frontmatter":{"title":"Guard Against Zero on Initial Render","impact":"HIGH","tags":"container, measure, initial-render"},"isInternal":false,"tokens":150,"sizeBytes":588},{"name":"container-no-excessive-use.md","path":"src/resources/skills/userinterface-wiki/rules/container-no-excessive-use.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/container-no-excessive-use.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-no-excessive-use.md -->","frontmatter":{"title":"Use Animated Bounds Sparingly","impact":"MEDIUM","tags":"container, performance, restraint"},"isInternal":false,"tokens":94,"sizeBytes":446},{"name":"container-overflow-hidden.md","path":"src/resources/skills/userinterface-wiki/rules/container-overflow-hidden.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/container-overflow-hidden.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-overflow-hidden.md -->","frontmatter":{"title":"Overflow Hidden on Animated Container","impact":"MEDIUM","tags":"container, overflow, clip"},"isInternal":false,"tokens":133,"sizeBytes":581},{"name":"container-transition-delay.md","path":"src/resources/skills/userinterface-wiki/rules/container-transition-delay.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/container-transition-delay.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-transition-delay.md -->","frontmatter":{"title":"Add Delay for Natural Container Transitions","impact":"LOW","tags":"container, delay, transition, natural"},"isInternal":false,"tokens":119,"sizeBytes":478},{"name":"container-two-div-pattern.md","path":"src/resources/skills/userinterface-wiki/rules/container-two-div-pattern.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/container-two-div-pattern.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-two-div-pattern.md -->","frontmatter":{"title":"Two-Div Pattern for Animated Bounds","impact":"HIGH","tags":"container, measure, motion"},"isInternal":false,"tokens":186,"sizeBytes":794},{"name":"container-use-resize-observer.md","path":"src/resources/skills/userinterface-wiki/rules/container-use-resize-observer.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/container-use-resize-observer.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontainer-use-resize-observer.md -->","frontmatter":{"title":"Use ResizeObserver for Measurement","impact":"MEDIUM","tags":"container, resize-observer, performance"},"isInternal":false,"tokens":272,"sizeBytes":1165},{"name":"context-cleanup-nodes.md","path":"src/resources/skills/userinterface-wiki/rules/context-cleanup-nodes.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/context-cleanup-nodes.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontext-cleanup-nodes.md -->","frontmatter":{"title":"Clean Up Audio Nodes After Playback","impact":"MEDIUM","tags":"context, cleanup, disconnect"},"isInternal":false,"tokens":91,"sizeBytes":395},{"name":"context-resume-suspended.md","path":"src/resources/skills/userinterface-wiki/rules/context-resume-suspended.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/context-resume-suspended.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontext-resume-suspended.md -->","frontmatter":{"title":"Resume Suspended AudioContext","impact":"HIGH","tags":"context, resume, suspended"},"isInternal":false,"tokens":110,"sizeBytes":455},{"name":"context-reuse-single.md","path":"src/resources/skills/userinterface-wiki/rules/context-reuse-single.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/context-reuse-single.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fcontext-reuse-single.md -->","frontmatter":{"title":"Reuse Single AudioContext","impact":"HIGH","tags":"context, audio-context, singleton"},"isInternal":false,"tokens":126,"sizeBytes":524},{"name":"design-filter-for-character.md","path":"src/resources/skills/userinterface-wiki/rules/design-filter-for-character.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/design-filter-for-character.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fdesign-filter-for-character.md -->","frontmatter":{"title":"Bandpass Filter for Sound Character","impact":"MEDIUM","tags":"design, filter, bandpass"},"isInternal":false,"tokens":121,"sizeBytes":497},{"name":"design-noise-for-percussion.md","path":"src/resources/skills/userinterface-wiki/rules/design-noise-for-percussion.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/design-noise-for-percussion.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fdesign-noise-for-percussion.md -->","frontmatter":{"title":"Noise for Percussive Sounds","impact":"MEDIUM","tags":"design, noise, percussion"},"isInternal":false,"tokens":161,"sizeBytes":544},{"name":"design-oscillator-for-tonal.md","path":"src/resources/skills/userinterface-wiki/rules/design-oscillator-for-tonal.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/design-oscillator-for-tonal.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fdesign-oscillator-for-tonal.md -->","frontmatter":{"title":"Oscillators for Tonal Sounds","impact":"MEDIUM","tags":"design, oscillator, tonal"},"isInternal":false,"tokens":113,"sizeBytes":410},{"name":"duration-max-300ms.md","path":"src/resources/skills/userinterface-wiki/rules/duration-max-300ms.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/duration-max-300ms.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fduration-max-300ms.md -->","frontmatter":{"title":"Max 300ms for User Actions","impact":"HIGH","tags":"duration, max, user-action"},"isInternal":false,"tokens":97,"sizeBytes":347},{"name":"duration-press-hover.md","path":"src/resources/skills/userinterface-wiki/rules/duration-press-hover.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/duration-press-hover.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fduration-press-hover.md -->","frontmatter":{"title":"Press and Hover 120-180ms","impact":"MEDIUM","tags":"duration, press, hover"},"isInternal":false,"tokens":97,"sizeBytes":372},{"name":"duration-shorten-before-curve.md","path":"src/resources/skills/userinterface-wiki/rules/duration-shorten-before-curve.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/duration-shorten-before-curve.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fduration-shorten-before-curve.md -->","frontmatter":{"title":"Shorten Duration Before Adjusting Curve","impact":"MEDIUM","tags":"duration, optimization"},"isInternal":false,"tokens":108,"sizeBytes":411},{"name":"duration-small-state.md","path":"src/resources/skills/userinterface-wiki/rules/duration-small-state.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/duration-small-state.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fduration-small-state.md -->","frontmatter":{"title":"Small State Changes 180-260ms","impact":"MEDIUM","tags":"duration, state-change"},"isInternal":false,"tokens":67,"sizeBytes":247},{"name":"easing-entrance-ease-out.md","path":"src/resources/skills/userinterface-wiki/rules/easing-entrance-ease-out.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/easing-entrance-ease-out.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-entrance-ease-out.md -->","frontmatter":{"title":"Ease-Out for Entrances","impact":"HIGH","tags":"easing, entrance, ease-out"},"isInternal":false,"tokens":96,"sizeBytes":378},{"name":"easing-exit-ease-in.md","path":"src/resources/skills/userinterface-wiki/rules/easing-exit-ease-in.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/easing-exit-ease-in.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-exit-ease-in.md -->","frontmatter":{"title":"Ease-In for Exits","impact":"HIGH","tags":"easing, exit, ease-in"},"isInternal":false,"tokens":96,"sizeBytes":353},{"name":"easing-for-state-change.md","path":"src/resources/skills/userinterface-wiki/rules/easing-for-state-change.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/easing-for-state-change.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-for-state-change.md -->","frontmatter":{"title":"Easing for System State Changes","impact":"HIGH","tags":"easing, state-change, system"},"isInternal":false,"tokens":121,"sizeBytes":451},{"name":"easing-linear-only-progress.md","path":"src/resources/skills/userinterface-wiki/rules/easing-linear-only-progress.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/easing-linear-only-progress.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-linear-only-progress.md -->","frontmatter":{"title":"Linear Easing Only for Progress","impact":"MEDIUM","tags":"easing, linear, progress"},"isInternal":false,"tokens":92,"sizeBytes":390},{"name":"easing-natural-decay.md","path":"src/resources/skills/userinterface-wiki/rules/easing-natural-decay.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/easing-natural-decay.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-natural-decay.md -->","frontmatter":{"title":"Exponential Ramps for Natural Decay","impact":"MEDIUM","impactDescription":"Linear ramps for decay produce abrupt, unnatural cutoffs; exponential ramps match perceptual expectations.","tags":"easing, decay, audio, animation"},"isInternal":false,"tokens":136,"sizeBytes":515},{"name":"easing-no-linear-motion.md","path":"src/resources/skills/userinterface-wiki/rules/easing-no-linear-motion.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/easing-no-linear-motion.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-no-linear-motion.md -->","frontmatter":{"title":"No Linear Easing for Motion","impact":"MEDIUM","impactDescription":"Linear easing for motion feels mechanical; reserve it for progress indicators where uniform speed is expected.","tags":"easing, linear, animation"},"isInternal":false,"tokens":116,"sizeBytes":521},{"name":"easing-transition-ease-in-out.md","path":"src/resources/skills/userinterface-wiki/rules/easing-transition-ease-in-out.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/easing-transition-ease-in-out.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Feasing-transition-ease-in-out.md -->","frontmatter":{"title":"Ease-In-Out for View Transitions","impact":"MEDIUM","tags":"easing, transition, ease-in-out"},"isInternal":false,"tokens":70,"sizeBytes":287},{"name":"envelope-exponential-decay.md","path":"src/resources/skills/userinterface-wiki/rules/envelope-exponential-decay.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/envelope-exponential-decay.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fenvelope-exponential-decay.md -->","frontmatter":{"title":"Exponential Decay for Natural Sound","impact":"HIGH","tags":"envelope, decay, exponential"},"isInternal":false,"tokens":109,"sizeBytes":383},{"name":"envelope-no-zero-target.md","path":"src/resources/skills/userinterface-wiki/rules/envelope-no-zero-target.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/envelope-no-zero-target.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fenvelope-no-zero-target.md -->","frontmatter":{"title":"No Zero Target for Exponential Ramps","impact":"HIGH","tags":"envelope, exponential, zero"},"isInternal":false,"tokens":122,"sizeBytes":407},{"name":"envelope-set-initial-value.md","path":"src/resources/skills/userinterface-wiki/rules/envelope-set-initial-value.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/envelope-set-initial-value.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fenvelope-set-initial-value.md -->","frontmatter":{"title":"Set Initial Value Before Ramp","impact":"MEDIUM","tags":"envelope, initial, glitch"},"isInternal":false,"tokens":125,"sizeBytes":418},{"name":"exit-key-required.md","path":"src/resources/skills/userinterface-wiki/rules/exit-key-required.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/exit-key-required.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fexit-key-required.md -->","frontmatter":{"title":"Unique Keys in AnimatePresence Lists","impact":"HIGH","tags":"exit, key, list"},"isInternal":false,"tokens":143,"sizeBytes":529},{"name":"exit-matches-initial.md","path":"src/resources/skills/userinterface-wiki/rules/exit-matches-initial.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/exit-matches-initial.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fexit-matches-initial.md -->","frontmatter":{"title":"Exit Mirrors Initial for Symmetry","impact":"MEDIUM","tags":"exit, initial, symmetry"},"isInternal":false,"tokens":151,"sizeBytes":490},{"name":"exit-prop-required.md","path":"src/resources/skills/userinterface-wiki/rules/exit-prop-required.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/exit-prop-required.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fexit-prop-required.md -->","frontmatter":{"title":"Exit Prop Required Inside AnimatePresence","impact":"HIGH","tags":"exit, prop, animate-presence"},"isInternal":false,"tokens":150,"sizeBytes":595},{"name":"exit-requires-wrapper.md","path":"src/resources/skills/userinterface-wiki/rules/exit-requires-wrapper.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/exit-requires-wrapper.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fexit-requires-wrapper.md -->","frontmatter":{"title":"AnimatePresence Wrapper Required","impact":"HIGH","tags":"exit, animate-presence, wrapper"},"isInternal":false,"tokens":109,"sizeBytes":437},{"name":"impl-default-subtle.md","path":"src/resources/skills/userinterface-wiki/rules/impl-default-subtle.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/impl-default-subtle.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fimpl-default-subtle.md -->","frontmatter":{"title":"Subtle Default Volume","impact":"MEDIUM","tags":"impl, volume, default"},"isInternal":false,"tokens":79,"sizeBytes":280},{"name":"impl-preload-audio.md","path":"src/resources/skills/userinterface-wiki/rules/impl-preload-audio.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/impl-preload-audio.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fimpl-preload-audio.md -->","frontmatter":{"title":"Preload Audio Files","impact":"MEDIUM","tags":"impl, preload, performance"},"isInternal":false,"tokens":154,"sizeBytes":607},{"name":"impl-reset-current-time.md","path":"src/resources/skills/userinterface-wiki/rules/impl-reset-current-time.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/impl-reset-current-time.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fimpl-reset-current-time.md -->","frontmatter":{"title":"Reset currentTime Before Replay","impact":"MEDIUM","tags":"impl, replay, current-time"},"isInternal":false,"tokens":94,"sizeBytes":404},{"name":"mode-pop-layout-for-lists.md","path":"src/resources/skills/userinterface-wiki/rules/mode-pop-layout-for-lists.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/mode-pop-layout-for-lists.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmode-pop-layout-for-lists.md -->","frontmatter":{"title":"popLayout for List Reordering","impact":"MEDIUM","tags":"mode, pop-layout, list"},"isInternal":false,"tokens":121,"sizeBytes":477},{"name":"mode-sync-layout-conflict.md","path":"src/resources/skills/userinterface-wiki/rules/mode-sync-layout-conflict.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/mode-sync-layout-conflict.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmode-sync-layout-conflict.md -->","frontmatter":{"title":"Mode \"sync\" Causes Layout Conflicts","impact":"MEDIUM","tags":"mode, sync, layout"},"isInternal":false,"tokens":149,"sizeBytes":589},{"name":"mode-wait-doubles-duration.md","path":"src/resources/skills/userinterface-wiki/rules/mode-wait-doubles-duration.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/mode-wait-doubles-duration.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmode-wait-doubles-duration.md -->","frontmatter":{"title":"Mode \"wait\" Doubles Duration","impact":"MEDIUM","tags":"mode, wait, duration"},"isInternal":false,"tokens":124,"sizeBytes":480},{"name":"morphing-aria-hidden.md","path":"src/resources/skills/userinterface-wiki/rules/morphing-aria-hidden.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/morphing-aria-hidden.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-aria-hidden.md -->","frontmatter":{"title":"Aria Hidden on Icon SVGs","impact":"LOW","tags":"morphing, a11y, aria"},"isInternal":false,"tokens":104,"sizeBytes":358},{"name":"morphing-consistent-viewbox.md","path":"src/resources/skills/userinterface-wiki/rules/morphing-consistent-viewbox.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/morphing-consistent-viewbox.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-consistent-viewbox.md -->","frontmatter":{"title":"Consistent ViewBox Size","impact":"HIGH","tags":"morphing, viewbox, svg"},"isInternal":false,"tokens":164,"sizeBytes":446},{"name":"morphing-group-variants.md","path":"src/resources/skills/userinterface-wiki/rules/morphing-group-variants.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/morphing-group-variants.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-group-variants.md -->","frontmatter":{"title":"Shared Group for Rotational Variants","impact":"HIGH","tags":"morphing, group, rotation"},"isInternal":false,"tokens":340,"sizeBytes":922},{"name":"morphing-jump-non-grouped.md","path":"src/resources/skills/userinterface-wiki/rules/morphing-jump-non-grouped.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/morphing-jump-non-grouped.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-jump-non-grouped.md -->","frontmatter":{"title":"Instant Jump for Non-Grouped Icons","impact":"MEDIUM","tags":"morphing, jump, group"},"isInternal":false,"tokens":145,"sizeBytes":581},{"name":"morphing-reduced-motion.md","path":"src/resources/skills/userinterface-wiki/rules/morphing-reduced-motion.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/morphing-reduced-motion.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-reduced-motion.md -->","frontmatter":{"title":"Reduced Motion Support for Icons","impact":"MEDIUM","tags":"morphing, a11y, reduced-motion"},"isInternal":false,"tokens":157,"sizeBytes":644},{"name":"morphing-spring-rotation.md","path":"src/resources/skills/userinterface-wiki/rules/morphing-spring-rotation.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/morphing-spring-rotation.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-spring-rotation.md -->","frontmatter":{"title":"Spring Physics for Rotation","impact":"MEDIUM","tags":"morphing, spring, rotation"},"isInternal":false,"tokens":117,"sizeBytes":516},{"name":"morphing-strokelinecap-round.md","path":"src/resources/skills/userinterface-wiki/rules/morphing-strokelinecap-round.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/morphing-strokelinecap-round.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-strokelinecap-round.md -->","frontmatter":{"title":"Round Stroke Line Caps","impact":"LOW","tags":"morphing, stroke, svg"},"isInternal":false,"tokens":82,"sizeBytes":323},{"name":"morphing-three-lines.md","path":"src/resources/skills/userinterface-wiki/rules/morphing-three-lines.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/morphing-three-lines.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-three-lines.md -->","frontmatter":{"title":"Icons Must Use Exactly Three Lines","impact":"HIGH","tags":"morphing, svg, structure"},"isInternal":false,"tokens":218,"sizeBytes":537},{"name":"morphing-use-collapsed.md","path":"src/resources/skills/userinterface-wiki/rules/morphing-use-collapsed.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/morphing-use-collapsed.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fmorphing-use-collapsed.md -->","frontmatter":{"title":"Use Collapsed Constant for Unused Lines","impact":"HIGH","tags":"morphing, collapsed, structure"},"isInternal":false,"tokens":160,"sizeBytes":511},{"name":"native-backdrop-styling.md","path":"src/resources/skills/userinterface-wiki/rules/native-backdrop-styling.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/native-backdrop-styling.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnative-backdrop-styling.md -->","frontmatter":{"title":"Use ::backdrop for Dialog Backgrounds","impact":"MEDIUM","tags":"native, backdrop, dialog"},"isInternal":false,"tokens":127,"sizeBytes":497},{"name":"native-placeholder-styling.md","path":"src/resources/skills/userinterface-wiki/rules/native-placeholder-styling.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/native-placeholder-styling.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnative-placeholder-styling.md -->","frontmatter":{"title":"Use ::placeholder for Input Styling","impact":"LOW","tags":"native, placeholder, input"},"isInternal":false,"tokens":125,"sizeBytes":515},{"name":"native-selection-styling.md","path":"src/resources/skills/userinterface-wiki/rules/native-selection-styling.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/native-selection-styling.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnative-selection-styling.md -->","frontmatter":{"title":"Use ::selection for Text Styling","impact":"LOW","tags":"native, selection, text"},"isInternal":false,"tokens":72,"sizeBytes":269},{"name":"nested-consistent-timing.md","path":"src/resources/skills/userinterface-wiki/rules/nested-consistent-timing.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/nested-consistent-timing.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnested-consistent-timing.md -->","frontmatter":{"title":"Coordinated Parent-Child Exit Timing","impact":"MEDIUM","tags":"nested, timing, exit"},"isInternal":false,"tokens":157,"sizeBytes":581},{"name":"nested-propagate-required.md","path":"src/resources/skills/userinterface-wiki/rules/nested-propagate-required.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/nested-propagate-required.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnested-propagate-required.md -->","frontmatter":{"title":"Propagate Prop for Nested AnimatePresence","impact":"HIGH","tags":"nested, propagate, exit"},"isInternal":false,"tokens":210,"sizeBytes":865},{"name":"none-context-menu-entrance.md","path":"src/resources/skills/userinterface-wiki/rules/none-context-menu-entrance.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/none-context-menu-entrance.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnone-context-menu-entrance.md -->","frontmatter":{"title":"No Entrance Animation for Context Menus","impact":"MEDIUM","tags":"none, context-menu, entrance"},"isInternal":false,"tokens":130,"sizeBytes":461},{"name":"none-high-frequency.md","path":"src/resources/skills/userinterface-wiki/rules/none-high-frequency.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/none-high-frequency.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnone-high-frequency.md -->","frontmatter":{"title":"No Animation for High-Frequency Interactions","impact":"HIGH","tags":"none, high-frequency, performance"},"isInternal":false,"tokens":132,"sizeBytes":539},{"name":"none-keyboard-navigation.md","path":"src/resources/skills/userinterface-wiki/rules/none-keyboard-navigation.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/none-keyboard-navigation.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fnone-keyboard-navigation.md -->","frontmatter":{"title":"No Animation for Keyboard Navigation","impact":"MEDIUM","tags":"none, keyboard, a11y"},"isInternal":false,"tokens":133,"sizeBytes":528},{"name":"param-click-duration.md","path":"src/resources/skills/userinterface-wiki/rules/param-click-duration.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/param-click-duration.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fparam-click-duration.md -->","frontmatter":{"title":"Click Duration 5-15ms","impact":"MEDIUM","tags":"param, click, duration"},"isInternal":false,"tokens":115,"sizeBytes":388},{"name":"param-filter-frequency-range.md","path":"src/resources/skills/userinterface-wiki/rules/param-filter-frequency-range.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/param-filter-frequency-range.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fparam-filter-frequency-range.md -->","frontmatter":{"title":"Click Filter 3000-6000Hz","impact":"LOW","tags":"param, filter, frequency"},"isInternal":false,"tokens":92,"sizeBytes":300},{"name":"param-q-value-range.md","path":"src/resources/skills/userinterface-wiki/rules/param-q-value-range.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/param-q-value-range.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fparam-q-value-range.md -->","frontmatter":{"title":"Filter Q Value 2-5","impact":"LOW","tags":"param, q-value, filter"},"isInternal":false,"tokens":90,"sizeBytes":287},{"name":"param-reasonable-gain.md","path":"src/resources/skills/userinterface-wiki/rules/param-reasonable-gain.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/param-reasonable-gain.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fparam-reasonable-gain.md -->","frontmatter":{"title":"Gain Under 1.0","impact":"MEDIUM","tags":"param, gain, clipping"},"isInternal":false,"tokens":95,"sizeBytes":291},{"name":"physics-active-state.md","path":"src/resources/skills/userinterface-wiki/rules/physics-active-state.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/physics-active-state.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fphysics-active-state.md -->","frontmatter":{"title":"Active State Scale Transform","impact":"HIGH","impactDescription":"Missing active state makes interactive elements feel unresponsive and reduces tactile feedback.","tags":"physics, interaction, active-state"},"isInternal":false,"tokens":114,"sizeBytes":532},{"name":"physics-no-excessive-stagger.md","path":"src/resources/skills/userinterface-wiki/rules/physics-no-excessive-stagger.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/physics-no-excessive-stagger.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fphysics-no-excessive-stagger.md -->","frontmatter":{"title":"Stagger Under 50ms Per Item","impact":"MEDIUM","impactDescription":"Excessive stagger delays list readiness and feels sluggish; keep per-item delay minimal.","tags":"physics, stagger, list-animation"},"isInternal":false,"tokens":113,"sizeBytes":457},{"name":"physics-spring-for-overshoot.md","path":"src/resources/skills/userinterface-wiki/rules/physics-spring-for-overshoot.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/physics-spring-for-overshoot.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fphysics-spring-for-overshoot.md -->","frontmatter":{"title":"Springs for Overshoot and Settle","impact":"HIGH","impactDescription":"Easing cannot produce natural overshoot; springs are required for organic bounce-and-settle motion.","tags":"physics, spring, overshoot"},"isInternal":false,"tokens":146,"sizeBytes":580},{"name":"physics-subtle-deformation.md","path":"src/resources/skills/userinterface-wiki/rules/physics-subtle-deformation.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/physics-subtle-deformation.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fphysics-subtle-deformation.md -->","frontmatter":{"title":"Subtle Squash and Stretch","impact":"MEDIUM","impactDescription":"Excessive squash/stretch feels cartoonish and distracts from the interface; subtle deformation adds polish.","tags":"physics, squash-stretch, deformation"},"isInternal":false,"tokens":128,"sizeBytes":500},{"name":"prefetch-hit-slop.md","path":"src/resources/skills/userinterface-wiki/rules/prefetch-hit-slop.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/prefetch-hit-slop.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-hit-slop.md -->","frontmatter":{"title":"Use hitSlop to Trigger Predictions Earlier","impact":"MEDIUM","tags":"prefetch, hit-slop, target"},"isInternal":false,"tokens":136,"sizeBytes":523},{"name":"prefetch-keyboard-tab.md","path":"src/resources/skills/userinterface-wiki/rules/prefetch-keyboard-tab.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/prefetch-keyboard-tab.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-keyboard-tab.md -->","frontmatter":{"title":"Prefetch on Keyboard Navigation","impact":"MEDIUM","tags":"prefetch, keyboard, tab, a11y"},"isInternal":false,"tokens":106,"sizeBytes":448},{"name":"prefetch-not-everything.md","path":"src/resources/skills/userinterface-wiki/rules/prefetch-not-everything.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/prefetch-not-everything.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-not-everything.md -->","frontmatter":{"title":"Prefetch by Intent, Not Viewport","impact":"HIGH","tags":"prefetch, viewport, intent, bundle-size"},"isInternal":false,"tokens":122,"sizeBytes":503},{"name":"prefetch-touch-fallback.md","path":"src/resources/skills/userinterface-wiki/rules/prefetch-touch-fallback.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/prefetch-touch-fallback.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-touch-fallback.md -->","frontmatter":{"title":"Fall Back Gracefully on Touch Devices","impact":"MEDIUM","tags":"prefetch, touch, mobile, fallback"},"isInternal":false,"tokens":162,"sizeBytes":663},{"name":"prefetch-trajectory-over-hover.md","path":"src/resources/skills/userinterface-wiki/rules/prefetch-trajectory-over-hover.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/prefetch-trajectory-over-hover.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-trajectory-over-hover.md -->","frontmatter":{"title":"Trajectory Prediction Over Hover Prefetching","impact":"HIGH","tags":"prefetch, trajectory, hover, performance"},"isInternal":false,"tokens":167,"sizeBytes":647},{"name":"prefetch-use-selectively.md","path":"src/resources/skills/userinterface-wiki/rules/prefetch-use-selectively.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/prefetch-use-selectively.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fprefetch-use-selectively.md -->","frontmatter":{"title":"Use Predictive Prefetching Selectively","impact":"MEDIUM","tags":"prefetch, selective, performance"},"isInternal":false,"tokens":98,"sizeBytes":466},{"name":"presence-disable-interactions.md","path":"src/resources/skills/userinterface-wiki/rules/presence-disable-interactions.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/presence-disable-interactions.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpresence-disable-interactions.md -->","frontmatter":{"title":"Disable Interactions on Exiting Elements","impact":"MEDIUM","tags":"presence, interaction, exit"},"isInternal":false,"tokens":134,"sizeBytes":576},{"name":"presence-hook-in-child.md","path":"src/resources/skills/userinterface-wiki/rules/presence-hook-in-child.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/presence-hook-in-child.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpresence-hook-in-child.md -->","frontmatter":{"title":"useIsPresent in Child Component","impact":"HIGH","tags":"presence, hook, component-hierarchy"},"isInternal":false,"tokens":138,"sizeBytes":550},{"name":"presence-safe-to-remove.md","path":"src/resources/skills/userinterface-wiki/rules/presence-safe-to-remove.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/presence-safe-to-remove.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpresence-safe-to-remove.md -->","frontmatter":{"title":"Call safeToRemove After Async Work","impact":"HIGH","tags":"presence, safe-to-remove, async"},"isInternal":false,"tokens":164,"sizeBytes":672},{"name":"pseudo-content-required.md","path":"src/resources/skills/userinterface-wiki/rules/pseudo-content-required.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/pseudo-content-required.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-content-required.md -->","frontmatter":{"title":"Content Property Required for Pseudo-Elements","impact":"HIGH","tags":"pseudo, content, before-after"},"isInternal":false,"tokens":113,"sizeBytes":461},{"name":"pseudo-first-line-styling.md","path":"src/resources/skills/userinterface-wiki/rules/pseudo-first-line-styling.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/pseudo-first-line-styling.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-first-line-styling.md -->","frontmatter":{"title":"Use ::first-line for Typographic Treatments","impact":"LOW","tags":"pseudo, first-line, typography"},"isInternal":false,"tokens":145,"sizeBytes":580},{"name":"pseudo-hit-target-expansion.md","path":"src/resources/skills/userinterface-wiki/rules/pseudo-hit-target-expansion.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/pseudo-hit-target-expansion.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-hit-target-expansion.md -->","frontmatter":{"title":"Hit Target Expansion with Pseudo-Elements","impact":"MEDIUM","tags":"pseudo, hit-target, accessibility"},"isInternal":false,"tokens":129,"sizeBytes":522},{"name":"pseudo-marker-styling.md","path":"src/resources/skills/userinterface-wiki/rules/pseudo-marker-styling.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/pseudo-marker-styling.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-marker-styling.md -->","frontmatter":{"title":"Use ::marker for Custom List Bullets","impact":"LOW","tags":"pseudo, marker, list, bullets"},"isInternal":false,"tokens":135,"sizeBytes":480},{"name":"pseudo-over-dom-node.md","path":"src/resources/skills/userinterface-wiki/rules/pseudo-over-dom-node.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/pseudo-over-dom-node.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-over-dom-node.md -->","frontmatter":{"title":"Pseudo-Elements Over DOM Nodes","impact":"MEDIUM","tags":"pseudo, dom, decorative"},"isInternal":false,"tokens":125,"sizeBytes":515},{"name":"pseudo-position-relative-parent.md","path":"src/resources/skills/userinterface-wiki/rules/pseudo-position-relative-parent.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/pseudo-position-relative-parent.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-position-relative-parent.md -->","frontmatter":{"title":"Position Relative Parent for Pseudo-Elements","impact":"HIGH","tags":"pseudo, position, relative"},"isInternal":false,"tokens":120,"sizeBytes":493},{"name":"pseudo-z-index-layering.md","path":"src/resources/skills/userinterface-wiki/rules/pseudo-z-index-layering.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/pseudo-z-index-layering.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fpseudo-z-index-layering.md -->","frontmatter":{"title":"Z-Index Layering for Pseudo-Elements","impact":"MEDIUM","tags":"pseudo, z-index, layering"},"isInternal":false,"tokens":159,"sizeBytes":548},{"name":"spring-for-gestures.md","path":"src/resources/skills/userinterface-wiki/rules/spring-for-gestures.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/spring-for-gestures.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fspring-for-gestures.md -->","frontmatter":{"title":"Springs for Gesture-Driven Motion","impact":"HIGH","tags":"spring, gesture, drag"},"isInternal":false,"tokens":127,"sizeBytes":445},{"name":"spring-for-interruptible.md","path":"src/resources/skills/userinterface-wiki/rules/spring-for-interruptible.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/spring-for-interruptible.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fspring-for-interruptible.md -->","frontmatter":{"title":"Springs for Interruptible Motion","impact":"HIGH","tags":"spring, interruptible, animation"},"isInternal":false,"tokens":132,"sizeBytes":493},{"name":"spring-params-balanced.md","path":"src/resources/skills/userinterface-wiki/rules/spring-params-balanced.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/spring-params-balanced.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fspring-params-balanced.md -->","frontmatter":{"title":"Balanced Spring Parameters","impact":"MEDIUM","tags":"spring, stiffness, damping"},"isInternal":false,"tokens":104,"sizeBytes":401},{"name":"spring-preserves-velocity.md","path":"src/resources/skills/userinterface-wiki/rules/spring-preserves-velocity.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/spring-preserves-velocity.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fspring-preserves-velocity.md -->","frontmatter":{"title":"Springs Preserve Input Velocity","impact":"MEDIUM","tags":"spring, velocity, drag"},"isInternal":false,"tokens":129,"sizeBytes":476},{"name":"staging-dim-background.md","path":"src/resources/skills/userinterface-wiki/rules/staging-dim-background.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/staging-dim-background.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fstaging-dim-background.md -->","frontmatter":{"title":"Dim Background for Focus","impact":"MEDIUM","impactDescription":"Transparent overlays fail to direct focus; dimmed backgrounds isolate the modal and reduce distraction.","tags":"staging, modal, overlay"},"isInternal":false,"tokens":100,"sizeBytes":464},{"name":"staging-one-focal-point.md","path":"src/resources/skills/userinterface-wiki/rules/staging-one-focal-point.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/staging-one-focal-point.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fstaging-one-focal-point.md -->","frontmatter":{"title":"Single Focal Point","impact":"MEDIUM","impactDescription":"Competing animations split attention and reduce clarity; one focal point guides the user effectively.","tags":"staging, focus, attention"},"isInternal":false,"tokens":134,"sizeBytes":537},{"name":"staging-z-index-hierarchy.md","path":"src/resources/skills/userinterface-wiki/rules/staging-z-index-hierarchy.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/staging-z-index-hierarchy.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fstaging-z-index-hierarchy.md -->","frontmatter":{"title":"Z-Index Layering for Animated Elements","impact":"MEDIUM","impactDescription":"Missing z-index causes tooltips and overlays to render behind other content, breaking the visual hierarchy.","tags":"staging, z-index, layering"},"isInternal":false,"tokens":117,"sizeBytes":498},{"name":"timing-consistent.md","path":"src/resources/skills/userinterface-wiki/rules/timing-consistent.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/timing-consistent.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftiming-consistent.md -->","frontmatter":{"title":"Consistent Timing for Similar Elements","impact":"CRITICAL","impactDescription":"Inconsistent timing across similar elements creates a disjointed, unpolished feel and undermines design system coherence.","tags":"timing, consistency, animation"},"isInternal":false,"tokens":129,"sizeBytes":600},{"name":"timing-no-entrance-context-menu.md","path":"src/resources/skills/userinterface-wiki/rules/timing-no-entrance-context-menu.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/timing-no-entrance-context-menu.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftiming-no-entrance-context-menu.md -->","frontmatter":{"title":"No Entrance Animation on Context Menus","impact":"HIGH","impactDescription":"Entrance animations on context menus delay access to options and feel unnecessary for ephemeral UI.","tags":"timing, context-menu, entrance"},"isInternal":false,"tokens":119,"sizeBytes":513},{"name":"timing-under-300ms.md","path":"src/resources/skills/userinterface-wiki/rules/timing-under-300ms.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/timing-under-300ms.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftiming-under-300ms.md -->","frontmatter":{"title":"User Animations Under 300ms","impact":"CRITICAL","impactDescription":"Exceeding 300ms for user-initiated actions degrades perceived responsiveness and makes the interface feel sluggish.","tags":"timing, duration, animation"},"isInternal":false,"tokens":121,"sizeBytes":489},{"name":"transition-name-cleanup.md","path":"src/resources/skills/userinterface-wiki/rules/transition-name-cleanup.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/transition-name-cleanup.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftransition-name-cleanup.md -->","frontmatter":{"title":"Clean Up View Transition Names","impact":"MEDIUM","tags":"view-transition, cleanup"},"isInternal":false,"tokens":130,"sizeBytes":576},{"name":"transition-name-required.md","path":"src/resources/skills/userinterface-wiki/rules/transition-name-required.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/transition-name-required.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftransition-name-required.md -->","frontmatter":{"title":"View Transition Name Required","impact":"HIGH","tags":"view-transition, transition-name"},"isInternal":false,"tokens":117,"sizeBytes":545},{"name":"transition-name-unique.md","path":"src/resources/skills/userinterface-wiki/rules/transition-name-unique.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/transition-name-unique.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftransition-name-unique.md -->","frontmatter":{"title":"Unique View Transition Names","impact":"HIGH","tags":"view-transition, unique, naming"},"isInternal":false,"tokens":94,"sizeBytes":418},{"name":"transition-over-js-library.md","path":"src/resources/skills/userinterface-wiki/rules/transition-over-js-library.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/transition-over-js-library.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftransition-over-js-library.md -->","frontmatter":{"title":"View Transitions Over JS Libraries","impact":"MEDIUM","tags":"view-transition, native, performance"},"isInternal":false,"tokens":142,"sizeBytes":622},{"name":"transition-style-pseudo-elements.md","path":"src/resources/skills/userinterface-wiki/rules/transition-style-pseudo-elements.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/transition-style-pseudo-elements.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftransition-style-pseudo-elements.md -->","frontmatter":{"title":"Style View Transition Pseudo-Elements","impact":"MEDIUM","tags":"view-transition, pseudo, styling"},"isInternal":false,"tokens":124,"sizeBytes":488},{"name":"type-antialiased-on-retina.md","path":"src/resources/skills/userinterface-wiki/rules/type-antialiased-on-retina.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-antialiased-on-retina.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-antialiased-on-retina.md -->","frontmatter":{"title":"Use Antialiased Font Smoothing","impact":"MEDIUM","tags":"type, rendering, antialiased"},"isInternal":false,"tokens":95,"sizeBytes":362},{"name":"type-disambiguation-stylistic-set.md","path":"src/resources/skills/userinterface-wiki/rules/type-disambiguation-stylistic-set.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-disambiguation-stylistic-set.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-disambiguation-stylistic-set.md -->","frontmatter":{"title":"Use Disambiguation Stylistic Set for UI","impact":"MEDIUM","tags":"type, stylistic-set, disambiguation"},"isInternal":false,"tokens":101,"sizeBytes":327},{"name":"type-font-display-swap.md","path":"src/resources/skills/userinterface-wiki/rules/type-font-display-swap.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-font-display-swap.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-font-display-swap.md -->","frontmatter":{"title":"Use font-display swap to Avoid Invisible Text","impact":"MEDIUM","tags":"type, font-display, loading, FOIT"},"isInternal":false,"tokens":150,"sizeBytes":578},{"name":"type-justify-with-hyphens.md","path":"src/resources/skills/userinterface-wiki/rules/type-justify-with-hyphens.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-justify-with-hyphens.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-justify-with-hyphens.md -->","frontmatter":{"title":"Pair Justified Text with Hyphens","impact":"MEDIUM","tags":"type, justify, hyphens, rivers"},"isInternal":false,"tokens":114,"sizeBytes":425},{"name":"type-letter-spacing-uppercase.md","path":"src/resources/skills/userinterface-wiki/rules/type-letter-spacing-uppercase.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-letter-spacing-uppercase.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-letter-spacing-uppercase.md -->","frontmatter":{"title":"Add Letter Spacing to Uppercase Text","impact":"MEDIUM","tags":"type, letter-spacing, uppercase, small-caps"},"isInternal":false,"tokens":132,"sizeBytes":474},{"name":"type-no-font-synthesis.md","path":"src/resources/skills/userinterface-wiki/rules/type-no-font-synthesis.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-no-font-synthesis.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-no-font-synthesis.md -->","frontmatter":{"title":"Disable Font Synthesis for Missing Styles","impact":"LOW","tags":"type, synthesis, italic, bold"},"isInternal":false,"tokens":82,"sizeBytes":353},{"name":"type-oldstyle-nums-for-prose.md","path":"src/resources/skills/userinterface-wiki/rules/type-oldstyle-nums-for-prose.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-oldstyle-nums-for-prose.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-oldstyle-nums-for-prose.md -->","frontmatter":{"title":"Oldstyle Numbers for Body Text","impact":"MEDIUM","tags":"type, numeric, oldstyle, prose"},"isInternal":false,"tokens":115,"sizeBytes":429},{"name":"type-opentype-contextual-alternates.md","path":"src/resources/skills/userinterface-wiki/rules/type-opentype-contextual-alternates.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-opentype-contextual-alternates.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-opentype-contextual-alternates.md -->","frontmatter":{"title":"Enable Contextual Alternates","impact":"MEDIUM","tags":"type, opentype, calt"},"isInternal":false,"tokens":85,"sizeBytes":344},{"name":"type-optical-sizing-auto.md","path":"src/resources/skills/userinterface-wiki/rules/type-optical-sizing-auto.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-optical-sizing-auto.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-optical-sizing-auto.md -->","frontmatter":{"title":"Keep Optical Sizing Auto","impact":"MEDIUM","tags":"type, variable-font, optical-sizing"},"isInternal":false,"tokens":109,"sizeBytes":454},{"name":"type-proper-fractions.md","path":"src/resources/skills/userinterface-wiki/rules/type-proper-fractions.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-proper-fractions.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-proper-fractions.md -->","frontmatter":{"title":"Use Typographic Fractions","impact":"LOW","tags":"type, fractions, numeric, opentype"},"isInternal":false,"tokens":81,"sizeBytes":292},{"name":"type-slashed-zero.md","path":"src/resources/skills/userinterface-wiki/rules/type-slashed-zero.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-slashed-zero.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-slashed-zero.md -->","frontmatter":{"title":"Slashed Zero for Disambiguation","impact":"MEDIUM","tags":"type, zero, disambiguation"},"isInternal":false,"tokens":92,"sizeBytes":328},{"name":"type-tabular-nums-for-data.md","path":"src/resources/skills/userinterface-wiki/rules/type-tabular-nums-for-data.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-tabular-nums-for-data.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-tabular-nums-for-data.md -->","frontmatter":{"title":"Tabular Numbers for Data Display","impact":"HIGH","tags":"type, numeric, tabular, alignment"},"isInternal":false,"tokens":113,"sizeBytes":446},{"name":"type-text-wrap-balance-headings.md","path":"src/resources/skills/userinterface-wiki/rules/type-text-wrap-balance-headings.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-text-wrap-balance-headings.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-text-wrap-balance-headings.md -->","frontmatter":{"title":"Balance Headings with text-wrap","impact":"MEDIUM","tags":"type, text-wrap, balance, headings"},"isInternal":false,"tokens":100,"sizeBytes":399},{"name":"type-text-wrap-pretty.md","path":"src/resources/skills/userinterface-wiki/rules/type-text-wrap-pretty.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-text-wrap-pretty.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-text-wrap-pretty.md -->","frontmatter":{"title":"Use text-wrap pretty for Body Text","impact":"MEDIUM","tags":"type, text-wrap, orphans, pretty"},"isInternal":false,"tokens":91,"sizeBytes":322},{"name":"type-underline-offset.md","path":"src/resources/skills/userinterface-wiki/rules/type-underline-offset.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-underline-offset.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-underline-offset.md -->","frontmatter":{"title":"Offset Underlines from Descenders","impact":"MEDIUM","tags":"type, underline, offset, decoration"},"isInternal":false,"tokens":116,"sizeBytes":477},{"name":"type-variable-weight-continuous.md","path":"src/resources/skills/userinterface-wiki/rules/type-variable-weight-continuous.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/type-variable-weight-continuous.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Ftype-variable-weight-continuous.md -->","frontmatter":{"title":"Use Continuous Weight Values with Variable Fonts","impact":"LOW","tags":"type, variable-font, weight"},"isInternal":false,"tokens":129,"sizeBytes":494},{"name":"ux-aesthetic-usability.md","path":"src/resources/skills/userinterface-wiki/rules/ux-aesthetic-usability.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-aesthetic-usability.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-aesthetic-usability.md -->","frontmatter":{"title":"Visual Polish Increases Perceived Usability","impact":"MEDIUM","tags":"ux, aesthetic, usability, polish"},"isInternal":false,"tokens":175,"sizeBytes":665},{"name":"ux-cognitive-load-reduce.md","path":"src/resources/skills/userinterface-wiki/rules/ux-cognitive-load-reduce.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-cognitive-load-reduce.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-cognitive-load-reduce.md -->","frontmatter":{"title":"Minimize Extraneous Cognitive Load","impact":"HIGH","tags":"ux, cognitive-load, simplicity, noise"},"isInternal":false,"tokens":281,"sizeBytes":1111},{"name":"ux-common-region-boundaries.md","path":"src/resources/skills/userinterface-wiki/rules/ux-common-region-boundaries.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-common-region-boundaries.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-common-region-boundaries.md -->","frontmatter":{"title":"Use Boundaries to Group Related Content","impact":"MEDIUM","tags":"ux, common-region, boundaries, grouping"},"isInternal":false,"tokens":266,"sizeBytes":1081},{"name":"ux-doherty-perceived-speed.md","path":"src/resources/skills/userinterface-wiki/rules/ux-doherty-perceived-speed.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-doherty-perceived-speed.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-doherty-perceived-speed.md -->","frontmatter":{"title":"Fake Speed When Actual Speed Isn't Possible","impact":"HIGH","tags":"ux, doherty, perceived-speed, skeleton"},"isInternal":false,"tokens":163,"sizeBytes":659},{"name":"ux-doherty-under-400ms.md","path":"src/resources/skills/userinterface-wiki/rules/ux-doherty-under-400ms.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-doherty-under-400ms.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-doherty-under-400ms.md -->","frontmatter":{"title":"Respond Within 400ms","impact":"CRITICAL","tags":"ux, doherty, latency, response-time"},"isInternal":false,"tokens":147,"sizeBytes":618},{"name":"ux-fitts-hit-area.md","path":"src/resources/skills/userinterface-wiki/rules/ux-fitts-hit-area.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-fitts-hit-area.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-fitts-hit-area.md -->","frontmatter":{"title":"Expand Hit Areas with Invisible Padding","impact":"HIGH","tags":"ux, fitts, hit-area, pseudo"},"isInternal":false,"tokens":130,"sizeBytes":525},{"name":"ux-fitts-target-size.md","path":"src/resources/skills/userinterface-wiki/rules/ux-fitts-target-size.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-fitts-target-size.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-fitts-target-size.md -->","frontmatter":{"title":"Size Interactive Targets for Easy Clicking","impact":"HIGH","tags":"ux, fitts, target-size"},"isInternal":false,"tokens":155,"sizeBytes":565},{"name":"ux-goal-gradient-progress.md","path":"src/resources/skills/userinterface-wiki/rules/ux-goal-gradient-progress.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-goal-gradient-progress.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-goal-gradient-progress.md -->","frontmatter":{"title":"Show Progress Toward Completion","impact":"HIGH","tags":"ux, goal-gradient, progress, motivation"},"isInternal":false,"tokens":176,"sizeBytes":702},{"name":"ux-hicks-minimize-choices.md","path":"src/resources/skills/userinterface-wiki/rules/ux-hicks-minimize-choices.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-hicks-minimize-choices.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-hicks-minimize-choices.md -->","frontmatter":{"title":"Minimize Choices to Reduce Decision Time","impact":"HIGH","tags":"ux, hicks, choices, cognitive-load"},"isInternal":false,"tokens":221,"sizeBytes":923},{"name":"ux-jakobs-familiar-patterns.md","path":"src/resources/skills/userinterface-wiki/rules/ux-jakobs-familiar-patterns.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-jakobs-familiar-patterns.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-jakobs-familiar-patterns.md -->","frontmatter":{"title":"Use Familiar UI Patterns","impact":"HIGH","tags":"ux, jakobs, familiarity, patterns"},"isInternal":false,"tokens":190,"sizeBytes":712},{"name":"ux-millers-chunking.md","path":"src/resources/skills/userinterface-wiki/rules/ux-millers-chunking.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-millers-chunking.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-millers-chunking.md -->","frontmatter":{"title":"Chunk Data into Groups of 5-9","impact":"HIGH","tags":"ux, millers, chunking, memory"},"isInternal":false,"tokens":139,"sizeBytes":464},{"name":"ux-pareto-prioritize-features.md","path":"src/resources/skills/userinterface-wiki/rules/ux-pareto-prioritize-features.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-pareto-prioritize-features.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-pareto-prioritize-features.md -->","frontmatter":{"title":"Prioritize the Critical 20% of Features","impact":"MEDIUM","tags":"ux, pareto, prioritization, features"},"isInternal":false,"tokens":202,"sizeBytes":759},{"name":"ux-peak-end-finish-strong.md","path":"src/resources/skills/userinterface-wiki/rules/ux-peak-end-finish-strong.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-peak-end-finish-strong.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-peak-end-finish-strong.md -->","frontmatter":{"title":"End Experiences with Clear Success States","impact":"MEDIUM","tags":"ux, peak-end, success, completion"},"isInternal":false,"tokens":170,"sizeBytes":723},{"name":"ux-postels-accept-messy-input.md","path":"src/resources/skills/userinterface-wiki/rules/ux-postels-accept-messy-input.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-postels-accept-messy-input.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-postels-accept-messy-input.md -->","frontmatter":{"title":"Accept Messy Input, Output Clean Data","impact":"MEDIUM","tags":"ux, postels, input, validation"},"isInternal":false,"tokens":218,"sizeBytes":878},{"name":"ux-pragnanz-simplify.md","path":"src/resources/skills/userinterface-wiki/rules/ux-pragnanz-simplify.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-pragnanz-simplify.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-pragnanz-simplify.md -->","frontmatter":{"title":"Simplify Complex Visuals into Clear Forms","impact":"MEDIUM","tags":"ux, pragnanz, simplicity, clarity"},"isInternal":false,"tokens":215,"sizeBytes":726},{"name":"ux-progressive-disclosure.md","path":"src/resources/skills/userinterface-wiki/rules/ux-progressive-disclosure.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-progressive-disclosure.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-progressive-disclosure.md -->","frontmatter":{"title":"Show What Matters Now, Reveal Complexity Later","impact":"HIGH","tags":"ux, progressive-disclosure, complexity"},"isInternal":false,"tokens":184,"sizeBytes":785},{"name":"ux-proximity-grouping.md","path":"src/resources/skills/userinterface-wiki/rules/ux-proximity-grouping.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-proximity-grouping.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-proximity-grouping.md -->","frontmatter":{"title":"Group Related Elements Spatially","impact":"HIGH","tags":"ux, proximity, grouping, layout"},"isInternal":false,"tokens":161,"sizeBytes":638},{"name":"ux-serial-position.md","path":"src/resources/skills/userinterface-wiki/rules/ux-serial-position.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-serial-position.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-serial-position.md -->","frontmatter":{"title":"Place Key Items First or Last","impact":"MEDIUM","tags":"ux, serial-position, navigation, order"},"isInternal":false,"tokens":176,"sizeBytes":683},{"name":"ux-similarity-consistency.md","path":"src/resources/skills/userinterface-wiki/rules/ux-similarity-consistency.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-similarity-consistency.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-similarity-consistency.md -->","frontmatter":{"title":"Similar Elements Should Look Alike","impact":"HIGH","tags":"ux, similarity, consistency, visual"},"isInternal":false,"tokens":164,"sizeBytes":664},{"name":"ux-teslers-complexity.md","path":"src/resources/skills/userinterface-wiki/rules/ux-teslers-complexity.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-teslers-complexity.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-teslers-complexity.md -->","frontmatter":{"title":"Move Complexity, Don't Hide It","impact":"MEDIUM","tags":"ux, teslers, complexity, simplicity"},"isInternal":false,"tokens":146,"sizeBytes":556},{"name":"ux-uniform-connectedness.md","path":"src/resources/skills/userinterface-wiki/rules/ux-uniform-connectedness.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-uniform-connectedness.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-uniform-connectedness.md -->","frontmatter":{"title":"Visually Connect Related Elements","impact":"MEDIUM","tags":"ux, connectedness, grouping, visual"},"isInternal":false,"tokens":254,"sizeBytes":983},{"name":"ux-von-restorff-emphasis.md","path":"src/resources/skills/userinterface-wiki/rules/ux-von-restorff-emphasis.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-von-restorff-emphasis.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-von-restorff-emphasis.md -->","frontmatter":{"title":"Make Important Elements Visually Distinct","impact":"HIGH","tags":"ux, von-restorff, emphasis, distinction"},"isInternal":false,"tokens":183,"sizeBytes":778},{"name":"ux-zeigarnik-show-incomplete.md","path":"src/resources/skills/userinterface-wiki/rules/ux-zeigarnik-show-incomplete.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/ux-zeigarnik-show-incomplete.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fux-zeigarnik-show-incomplete.md -->","frontmatter":{"title":"Show Incomplete State to Drive Completion","impact":"MEDIUM","tags":"ux, zeigarnik, incomplete, engagement"},"isInternal":false,"tokens":172,"sizeBytes":746},{"name":"visual-animate-shadow-pseudo.md","path":"src/resources/skills/userinterface-wiki/rules/visual-animate-shadow-pseudo.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/visual-animate-shadow-pseudo.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-animate-shadow-pseudo.md -->","frontmatter":{"title":"Animate Shadows via Pseudo-Element Opacity","impact":"MEDIUM","tags":"visual, shadow, animation, performance"},"isInternal":false,"tokens":254,"sizeBytes":942},{"name":"visual-border-alpha-colors.md","path":"src/resources/skills/userinterface-wiki/rules/visual-border-alpha-colors.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/visual-border-alpha-colors.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-border-alpha-colors.md -->","frontmatter":{"title":"Use Semi-Transparent Borders for Subtle Separation","impact":"MEDIUM","tags":"visual, border, alpha, separation"},"isInternal":false,"tokens":120,"sizeBytes":454},{"name":"visual-button-shadow-anatomy.md","path":"src/resources/skills/userinterface-wiki/rules/visual-button-shadow-anatomy.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/visual-button-shadow-anatomy.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-button-shadow-anatomy.md -->","frontmatter":{"title":"Use Full Shadow Anatomy on Buttons","impact":"HIGH","tags":"visual, shadow, button, depth, gradient"},"isInternal":false,"tokens":512,"sizeBytes":1525},{"name":"visual-concentric-radius.md","path":"src/resources/skills/userinterface-wiki/rules/visual-concentric-radius.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/visual-concentric-radius.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-concentric-radius.md -->","frontmatter":{"title":"Concentric Border Radius for Nested Elements","impact":"HIGH","tags":"visual, border-radius, concentric, nesting"},"isInternal":false,"tokens":192,"sizeBytes":757},{"name":"visual-consistent-spacing-scale.md","path":"src/resources/skills/userinterface-wiki/rules/visual-consistent-spacing-scale.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/visual-consistent-spacing-scale.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-consistent-spacing-scale.md -->","frontmatter":{"title":"Use a Consistent Spacing Scale","impact":"HIGH","tags":"visual, spacing, scale, consistency"},"isInternal":false,"tokens":216,"sizeBytes":661},{"name":"visual-layered-shadows.md","path":"src/resources/skills/userinterface-wiki/rules/visual-layered-shadows.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/visual-layered-shadows.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-layered-shadows.md -->","frontmatter":{"title":"Layer Multiple Shadows for Realistic Depth","impact":"HIGH","tags":"visual, shadow, layered, depth"},"isInternal":false,"tokens":216,"sizeBytes":656},{"name":"visual-no-pure-black-shadow.md","path":"src/resources/skills/userinterface-wiki/rules/visual-no-pure-black-shadow.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/visual-no-pure-black-shadow.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-no-pure-black-shadow.md -->","frontmatter":{"title":"Use Neutral Colors for Shadows, Not Pure Black","impact":"MEDIUM","tags":"visual, shadow, color, neutral"},"isInternal":false,"tokens":142,"sizeBytes":462},{"name":"visual-shadow-direction.md","path":"src/resources/skills/userinterface-wiki/rules/visual-shadow-direction.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/visual-shadow-direction.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-shadow-direction.md -->","frontmatter":{"title":"Consistent Shadow Direction Across UI","impact":"HIGH","tags":"visual, shadow, direction, light-source"},"isInternal":false,"tokens":256,"sizeBytes":701},{"name":"visual-shadow-matches-elevation.md","path":"src/resources/skills/userinterface-wiki/rules/visual-shadow-matches-elevation.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/visual-shadow-matches-elevation.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fvisual-shadow-matches-elevation.md -->","frontmatter":{"title":"Shadow Size Indicates Elevation","impact":"MEDIUM","tags":"visual, shadow, elevation, hierarchy"},"isInternal":false,"tokens":190,"sizeBytes":548},{"name":"weight-duration-matches-action.md","path":"src/resources/skills/userinterface-wiki/rules/weight-duration-matches-action.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/weight-duration-matches-action.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fweight-duration-matches-action.md -->","frontmatter":{"title":"Sound Duration Matches Action Duration","impact":"MEDIUM","tags":"weight, duration, action"},"isInternal":false,"tokens":118,"sizeBytes":504},{"name":"weight-match-action.md","path":"src/resources/skills/userinterface-wiki/rules/weight-match-action.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/rules/weight-match-action.md","title":"Rules Skill","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2Frules%2Fweight-match-action.md -->","frontmatter":{"title":"Match Sound Weight to Action","impact":"MEDIUM","tags":"weight, action, importance"},"isInternal":false,"tokens":124,"sizeBytes":519},{"name":"SKILL.md","path":"src/resources/skills/userinterface-wiki/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/userinterface-wiki/SKILL.md","title":"userinterface-wiki","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fuserinterface-wiki%2FSKILL.md -->","frontmatter":{"name":"userinterface-wiki","description":"UI/UX best practices for web interfaces. Use when reviewing animations, CSS, audio, typography, UX patterns, prefetching, or icon implementations. Covers 11 categories from animation principles to typography. Outputs file:line findings.","license":"MIT","metadata":{"author":"raphael-salaja","version":"3.0.0"}},"isInternal":false,"tokens":3516,"sizeBytes":14179},{"name":"SKILL.md","path":"src/resources/skills/verify-before-complete/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/verify-before-complete/SKILL.md","title":"verify-before-complete","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fverify-before-complete%2FSKILL.md -->","frontmatter":{"name":"verify-before-complete","description":"Block completion claims until verification evidence has been produced in the current message. Use before marking a task/slice/milestone complete, before creating a commit or PR, before saying \"it works\" or \"tests pass\", and any time you are about to claim work is done. The rule is: evidence before claims, always — running the verification must happen now, not \"earlier in the session\". Fresh output or no claim."},"isInternal":false,"tokens":1257,"sizeBytes":5214},{"name":"SKILL.md","path":"src/resources/skills/web-design-guidelines/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/web-design-guidelines/SKILL.md","title":"web-design-guidelines","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fweb-design-guidelines%2FSKILL.md -->","frontmatter":{"name":"web-design-guidelines","description":"Review UI code for Web Interface Guidelines compliance. Use when asked to \"review my UI\", \"check accessibility\", \"audit design\", \"review UX\", or \"check my site against best practices\".","metadata":{"author":"vercel","version":"1.0.0","argument-hint":"<file-or-pattern>"}},"isInternal":false,"tokens":268,"sizeBytes":1231},{"name":"SKILL.md","path":"src/resources/skills/web-quality-audit/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/web-quality-audit/SKILL.md","title":"web-quality-audit","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fweb-quality-audit%2FSKILL.md -->","frontmatter":{"name":"web-quality-audit","description":"Comprehensive web quality audit covering performance, accessibility, SEO, and best practices. Use when asked to \"audit my site\", \"review web quality\", \"run lighthouse audit\", \"check page quality\", or \"optimize my website\".","license":"MIT","metadata":{"author":"web-quality-skills","version":"1.0"}},"isInternal":false,"tokens":1555,"sizeBytes":6549},{"name":"SKILL.md","path":"src/resources/skills/write-docs/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/write-docs/SKILL.md","title":"write-docs","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fwrite-docs%2FSKILL.md -->","frontmatter":{"name":"write-docs","description":"Collaborative document authoring workflow for proposals, technical specs, decision docs, README sections, ADRs, and long-form prose that must work for fresh readers. Use when asked to \"write the docs\", \"draft a proposal\", \"write a spec\", \"write an RFC\", \"write the README\", or when a document needs to be understandable by someone without this session's context. Three stages: gather context, iterate on structure, reader-test for a stranger."},"isInternal":false,"tokens":1299,"sizeBytes":5458},{"name":"SKILL.md","path":"src/resources/skills/write-milestone-brief/SKILL.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/src/resources/skills/write-milestone-brief/SKILL.md","title":"write-milestone-brief","category":"anthropic-skill","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=src%2Fresources%2Fskills%2Fwrite-milestone-brief%2FSKILL.md -->","frontmatter":{"name":"write-milestone-brief","description":"Synthesize the current conversation into a milestone brief (PRD). Writes to `M###-CONTEXT.md` by default, or files a GitHub issue only with explicit user confirmation. Use when asked to \"turn this into a PRD\", \"draft a milestone brief\", \"capture this context\", \"write it up\", or when enough has been discussed to commit the plan to paper. Does not interview — it synthesizes what is already known."},"isInternal":false,"tokens":1876,"sizeBytes":8493},{"name":"domain.md","path":"docs/agents/domain.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/docs/agents/domain.md","title":"Subagent: domain","category":"subagent-persona","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=docs%2Fagents%2Fdomain.md -->","isInternal":false,"tokens":324,"sizeBytes":1321},{"name":"issue-tracker.md","path":"docs/agents/issue-tracker.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/docs/agents/issue-tracker.md","title":"Subagent: issue-tracker","category":"subagent-persona","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=docs%2Fagents%2Fissue-tracker.md -->","isInternal":false,"tokens":413,"sizeBytes":1449},{"name":"triage-labels.md","path":"docs/agents/triage-labels.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/docs/agents/triage-labels.md","title":"Subagent: triage-labels","category":"subagent-persona","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=docs%2Fagents%2Ftriage-labels.md -->","isInternal":false,"tokens":366,"sizeBytes":1569},{"name":"README.md","path":"packages/mcp-server/README.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/packages/mcp-server/README.md","title":"mcp-server Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=packages%2Fmcp-server%2FREADME.md -->","isInternal":false,"tokens":2552,"sizeBytes":10504},{"name":"README.md","path":"packages/rpc-client/README.md","rawUrl":"https://raw.githubusercontent.com/gsd-build/gsd-2/HEAD/packages/rpc-client/README.md","title":"rpc-client Documentation","category":"plugin-manifest","format":"markdown","content":"<!-- Skill available on-demand via /api/skills/gsd-build/gsd-2?path=packages%2Frpc-client%2FREADME.md -->","isInternal":false,"tokens":980,"sizeBytes":4997}],"systemPromptSnippet":"<yakaai_skills repo=\"gsd-build/gsd-2\">\n<!-- File: gsd-orchestrator/SKILL.md (Tokens: ~2201 | Category: anthropic-skill) -->\n---\nname: gsd-orchestrator\ndescription: >\n  Build software products autonomously via GSD headless mode. Handles the full\n  lifecycle: write a spec, launch a build, poll for completion, handle blockers,\n  track costs, and verify the result. Use when asked to \"build something\",\n  \"create a project\", \"run gsd\", \"check build status\", or any task that\n  requires autonomous software development via subprocess.\nmetadata:\n  openclaw:\n    requires:\n      bins: [gsd]\n    install:\n      kind: node\n      package: gsd-pi\n      bins: [gsd]\n---\n\n<objective>\nYou are an autonomous agent that builds software by orchestrating GSD as a subprocess.\nGSD is a headless CLI that plans, codes, tests, and ships software from a spec.\nYou control it via shell commands, exit codes, and JSON output — no SDK, no RPC.\n</objective>\n\n<mental_model>\nGSD headless is a subprocess you launch and monitor. Think of it like a junior developer\nyou hand a spec to:\n\n1. You write the spec (what to build)\n2. You launch the build (`gsd headless ... new-milestone --context spec.md --auto`)\n3. You wait for it to finish (exit code tells you the outcome)\n4. You check the result (query state, inspect files, verify deliverables)\n5. If blocked, you intervene (steer, supply answers, or escalate)\n\nThe subprocess handles all planning, coding, testing, and git commits internally.\nYou never write application code yourself — GSD does that.\n</mental_model>\n\n<critical_rules>\n- **Flags before command.** `gsd headless [--flags] [command] [args]`. Flags after the command are ignored.\n- **Redirect stderr.** JSON output goes to stdout. Progress goes to stderr. Always `2>/dev/null` when parsing JSON.\n- **Check exit codes.** 0=success, 1=error, 10=blocked (needs you), 11=cancelled.\n- **Use `query` to poll.** Instant (~50ms), no LLM cost. Use it between steps, not `auto` for status.\n- **Budget awareness.** Track `cost.total` from query results. Set limits before launching long runs.\n- **One project directory per build.** Each GSD project needs its own directory with a `.gsd/` folder.\n</critical_rules>\n\n<routing>\nRoute based on what you need to do:\n\n**Build something from scratch:**\nRead `workflows/build-from-spec.md` — write spec, init directory, launch, monitor, verify.\n\n**Check on a running or completed build:**\nRead `workflows/monitor-and-poll.md` — query state, interpret phases, handle blockers.\n\n**Execute with fine-grained control:**\nRead `workflows/step-by-step.md` — run one unit at a time with decision points.\n\n**Understand the JSON output:**\nRead `references/json-result.md` — field reference for HeadlessJsonResult.\n\n**Pre-supply answers or secrets:**\nRead `references/answer-injection.md` — answer file schema and injection mechanism.\n\n**Look up a specific command:**\nRead `references/commands.md` — full command reference with flags and examples.\n</routing>\n\n<quick_reference>\n\n**Launch a full build (spec to working code):**\n```bash\nmkdir -p /tmp/my-project && cd /tmp/my-project && git init\ncat > spec.md << 'EOF'\n# Your Product Spec Here\nBuild a ...\nEOF\ngsd headless --output-format json --context spec.md new-milestone --auto 2>/dev/null\n```\n\n**Check project state (instant, free):**\n```bash\ncd /path/to/project\ngsd headless query | jq '{phase: .state.phase, progress: .state.progress, cost: .cost.total}'\n```\n\n**Resume work on an existing project:**\n```bash\ncd /path/to/project\ngsd headless --output-format json auto 2>/dev/null\n```\n\n**Run one step at a time:**\n```bash\nRESULT=$(gsd headless --output-format json next 2>/dev/null)\necho \"$RESULT\" | jq '{status: .status, phase: .phase, cost: .cost.total}'\n```\n\n</quick_reference>\n\n<exit_codes>\n| Code | Meaning | Your action |\n|------|---------|-------------|\n| `0`  | Success | Check deliverables, verify output, report completion |\n| `1`  | Error or timeout | Inspect stderr, check `.gsd/STATE.md`, retry or escalate |\n| `10` | Blocked | Query state for blocker details, steer around it or escalate to human |\n| `11` | Cancelled | Process was interrupted — resume with `--resume <sessionId>` or restart |\n</exit_codes>\n\n<project_structure>\nGSD creates and manages all state in `.gsd/`:\n```\n.gsd/\n  PROJECT.md          # What this project is\n  REQUIREMENTS.md     # Capability contract\n  DECISIONS.md        # Architectural decisions (append-only)\n  KNOWLEDGE.md        # Persistent project knowledge (manual rules, memory-projected patterns/lessons)\n  STATE.md            # Current phase and next action\n  milestones/\n    M001-xxxxx/\n      M001-xxxxx-CONTEXT.md    # Scope, constraints, assumptions\n      M001-xxxxx-ROADMAP.md    # Slices with checkboxes\n      M001-xxxxx-SUMMARY.md    # Completion summary\n      slices/S01/\n        S01-PLAN.md            # Tasks\n        S01-SUMMARY.md         # Slice summary\n        tasks/\n          T01-PLAN.md          # Individual task spec\n          T01-SUMMARY.md       # Task completion summary\n```\n\nState is derived from files on disk — checkboxes in ROADMAP.md and PLAN.md are the source of truth for completion. You never need to edit these files. GSD manages them. But you can read them to understand progress.\n</project_structure>\n\n<flags>\n| Flag | Description |\n|------|-------------|\n| `--output-format <fmt>` | `text` (default), `json` (structured result at exit), `stream-json` (JSONL events) |\n| `--json` | Alias for `--output-format stream-json` — JSONL event stream to stdout |\n| `--bare` | Skip CLAUDE.md, AGENTS.md, user settings, user skills. Use for CI/ecosystem runs. |\n| `--resume <id>` | Resume a prior headless session by its session ID |\n| `--timeout N` | Overall timeout in ms (default: 300000, use 0 to disable) |\n| `--model ID` | Override LLM model |\n| `--supervised` | Forward interactive UI requests to orchestrator via stdout/stdin |\n| `--response-timeout N` | Timeout (ms) for orchestrator response in supervised mode (default: 30000) |\n| `--answers <path>` | Pre-supply answers and secrets from JSON file |\n| `--events <types>` | Filter JSONL to specific event types (comma-separated, implies `--json`) |\n| `--verbose` | Show tool calls in progress output |\n| `--context <path>` | Spec file path for `new-milestone` (use `-` for stdin) |\n| `--context-text <text>` | Inline spec text for `new-milestone` |\n| `--auto` | Chain into auto-mode after `new-milestone` |\n</flags>\n\n<answer_injection>\nPre-supply answers and secrets for fully autonomous runs:\n\n```bash\ngsd headless --answers answers.json --output-format json auto 2>/dev/null\n```\n\n```json\n{\n  \"questions\": { \"question_id\": \"selected_option\" },\n  \"secrets\": { \"API_KEY\": \"sk-...\" },\n  \"defaults\": { \"strategy\": \"first_option\" }\n}\n```\n\n- **questions** — question ID to answer (string for single-select, string[] for multi-select)\n- **secrets** — env var to value, injected into child process environment\n- **defaults.strategy** — `\"first_option\"` (default) or `\"cancel\"` for unmatched questions\n\nSee `references/answer-injection.md` for the full mechanism.\n</answer_injection>\n\n<event_streaming>\nFor real-time monitoring, use JSONL event streaming:\n\n```bash\ngsd headless --json auto 2>/dev/null | while read -r line; do\n  TYPE=$(echo \"$line\" | jq -r '.type')\n  case \"$TYPE\" in\n    tool_execution_start) echo \"Tool: $(echo \"$line\" | jq -r '.toolName')\" ;;\n    extension_ui_request) echo \"GSD: $(echo \"$line\" | jq -r '.message // .title // empty')\" ;;\n    agent_end) echo \"Session ended\" ;;\n  esac\ndone\n```\n\nFilter to specific events: `--events agent_end,execution_complete,extension_ui_request`\n\nAvailable types: `agent_start`, `agent_end`, `tool_execution_start`, `tool_execution_end`,\n`tool_execution_update`, `extension_ui_request`, `message_start`, `message_end`,\n`message_update`, `turn_start`, `turn_end`, `cost_update`, `execution_complete`.\n</event_streaming>\n\n<all_commands>\n| Command | Purpose |\n|---------|---------|\n| `auto` | Run all queued units until milestone complete or blocked (default) |\n| `next` | Run exactly one unit, then exit |\n| `query` | Instant JSON snapshot — state, next dispatch, costs (no LLM, ~50ms) |\n| `new-milestone` | Create milestone from spec file |\n| `dispatch <phase>` | Force specific phase (research, plan, execute, complete, reassess, uat, replan) |\n| `stop` / `pause` | Control auto-mode |\n| `steer <desc>` | Hard-steer plan mid-execution |\n| `skip` / `undo` | Unit control |\n| `queue` | Queue/reorder milestones |\n| `history` | View execution history |\n| `doctor` | Health check + auto-fix |\n| `knowledge <rule\\|pattern\\|lesson>` | Add persistent project knowledge |\n\nSee `references/commands.md` for the complete reference.\n</all_commands>\n\n<!-- File: src/resources/extensions/gsd/docs/claude-marketplace-import.md (Tokens: ~1203 | Category: anthropic-skill) -->\n# Claude Marketplace Import\n\nThis document describes the Claude marketplace import feature in GSD: what it reads, what it imports, what it persists, and what it does not translate into active GSD/Pi runtime behavior.\n\n---\n\n## What this feature does\n\nGSD can read Claude Code marketplace catalogs, inspect the plugins they reference, and import selected Claude skills into GSD/Pi while preserving Claude-style namespace identity.\n\nThe interactive entry point is:\n\n```text\n/gsd prefs import-claude\n```\n\nYou can also choose scope explicitly:\n\n```text\n/gsd prefs import-claude global\n/gsd prefs import-claude project\n```\n\n---\n\n## Claude Code model this feature follows\n\nAnthropic documents Claude marketplaces as sources users add with:\n\n```text\n/plugin marketplace add <github repo or local path>\n```\n\nA marketplace contains a catalog at:\n\n```text\n.claude-plugin/marketplace.json\n```\n\nAnthropic distinguishes between:\n\n- **Marketplace source** — where Claude fetches `marketplace.json`\n- **Plugin source** — where Claude fetches each plugin listed in that marketplace\n- **Installed plugin cache** — Claude copies installed plugin payloads into:\n\n```text\n~/.claude/plugins/cache\n```\n\nAnthropic also documents user-added marketplace sources under:\n\n```text\n~/.claude/plugins/marketplaces\n```\n\nGSD aligns its Claude import flow to that model.\n\n---\n\n## Where GSD looks\n\nFor Claude plugin and marketplace material, GSD prefers Claude-managed locations first:\n\n1. `~/.claude/plugins/marketplaces`\n2. `~/.claude/plugins/cache`\n3. `~/.claude/plugins`\n\nAfter that, GSD still allows local clone-style convenience paths such as sibling repos or `~/repos/...` paths. Those fallbacks remain supported for developer workflows, but they are not the primary Claude storage model.\n\n---\n\n## What GSD imports\n\n### Imported into GSD/Pi settings\n\n- Claude skills discovered directly from configured skill roots\n- Marketplace-derived skills\n\nImported marketplace skills preserve canonical namespace identity, for example:\n\n```text\npython3-development:stinkysnake\nscientific-method:experiment-protocol\n```\n\n### Discovered, modeled, and validated\n\n- Marketplace-derived agents\n\n### Discovered but not translated into active Pi-native runtime behavior\n\n- hooks\n- MCP server definitions\n- LSP server definitions\n- other plugin metadata that does not currently map directly into active GSD/Pi runtime surfaces\n\n---\n\n## Import flow\n\nThe import flow does the following:\n\n1. discover Claude skills and marketplace/plugin roots\n2. identify marketplace roots by checking for `.claude-plugin/marketplace.json`\n3. inspect discovered plugins and inventory their components\n4. let you select components to import\n5. validate the selection for canonical conflicts and ambiguity\n6. persist imported resources into GSD/Pi settings\n\n---\n\n## Namespace behavior\n\nGSD preserves Claude plugin namespace semantics rather than flattening plugin components into anonymous global names.\n\n### Canonical references\n\nCanonical references remain available for imported components:\n\n- skills: `plugin-name:skill-name`\n- agents: `plugin-name:agent-name`\n\n### Shorthand\n\nGSD supports shorthand lookup when it is unambiguous.\n\n### Local-first resolution\n\nWhen a namespaced component refers to another component by bare name, GSD tries the same plugin namespace first before broader lookup.\n\n---\n\n## Important safeguard: marketplace agent directories are not stored as package sources\n\nClaude plugin agent directories are markdown agent-definition directories, for example:\n\n```text\n.../plugins/python3-development/agents\n```\n\nGSD does **not** persist imported marketplace agent directories into:\n\n```json\nsettings.packages\n```\n\nThis is intentional.\n\n### Why\n\nPersisting an `.../agents` directory into `settings.packages` can cause Pi startup to treat that directory as an extension/package root. In real host validation, that produced extension loader failures such as:\n\n```text\nCannot find module '.../agents'\n```\n\nGSD now avoids writing those entries.\n\n---\n\n## Settings effects\n\n### Skills\n\nImported skills are persisted into Pi skill settings. Depending on the selection path, they may also be added to GSD preferences.\n\n### Marketplace agents\n\nMarketplace agents remain part of the import model and validation surface, but their `agents/` directories are not persisted as package roots.\n\n---\n\n## Diagnostics\n\nGSD distinguishes between:\n\n- **canonical conflicts** — hard errors\n- **shorthand overlaps** — warnings when canonical names remain distinct\n- **alias conflicts** — diagnostics for alias collisions or shadowing\n\nThis allows imported marketplace content to be validated without reporting valid overlap as fatal breakage.\n\n---\n\n## Verification status of this feature\n\nThis feature has been verified in three ways:\n\n1. **Contract/unit tests** for parsing, namespacing, resolution, diagnostics, and import behavior\n2. **Portable integration-style tests** using local or cloned marketplace fixtures\n3. **Real host validation** against the installed `gsd` binary and actual Claude-managed directories on the host machine\n\nReal host validation included:\n\n- clean startup of the installed `gsd` binary after fixing stale bad settings\n- successful invocation of an imported skill (`/stinkysnake`)\n- successful execution of `/gsd prefs import-claude global`\n- verification that imported marketplace agent directories were **not** reintroduced into `settings.packages`\n\n---\n\n## Current limitations\n\n- GSD does not yet translate every Claude plugin component type into active Pi-native runtime behavior\n- marketplace-derived agents are not persisted as package roots, by design\n- clone-style local fallbacks still exist for developer convenience, even though Claude-managed marketplace/plugin locations are preferred first\n\n---\n\n## References\n\n- Anthropic: Claude Code settings\n- Anthropic: Create and distribute a plugin marketplace\n- Anthropic: Plugins and plugin reference\n\n<!-- File: src/resources/extensions/gsd/docs/COORDINATION.md (Tokens: ~461 | Category: anthropic-skill) -->\n# Auto-mode coordination is single-host\n\nThe DB-backed coordination tables introduced by Phase B (`workers`,\n`milestone_leases`, `unit_dispatches`, `cancellation_requests`,\n`command_queue`) and the supporting `runtime_kv` table from Phase C all\nrely on **shared SQLite WAL on local disk**. They do not work across\nmachines.\n\n## Why single-host only\n\n- SQLite WAL coordination — the locking primitives that make\n  `claimMilestoneLease`, `recordDispatchClaim`, and `claimNextCommand`\n  atomic — is local-disk only. Network filesystems (NFS, SMB, S3FS) and\n  fuse mounts break the lock semantics that the WAL relies on.\n- Heartbeat TTL (`workers.last_heartbeat_at`) compares timestamps written\n  with SQLite wall-clock time (`datetime('now')`). Across machines without\n  wall-clock synchronization (for example NTP/chrony), TTL filtering can\n  produce phantom-active or premature-crashed verdicts. Monotonic clocks\n  are not used for these comparisons.\n- Fencing tokens (`milestone_leases.fencing_token`) are monotonically\n  ordered by SQL within a single transaction. Cross-host races could\n  produce duplicate tokens if two SQLite processes opened the same DB\n  on a network mount.\n\n## What does work\n\n- Multiple `gsd auto` worker processes on the **same machine**, sharing\n  the project's SQLite DB via WAL. The lease check refuses concurrent\n  claims on the same milestone; the dispatch ledger's partial unique\n  index refuses double-claims of the same unit.\n- A single `gsd auto` worker plus arbitrary read-only consumers\n  (dashboards, doctors) on the same machine.\n- Worktree-based parallelism on the same machine, where each worker\n  holds a different milestone lease.\n\n## Multi-host alternatives\n\nIf you need to coordinate `gsd auto` workers across machines, you need\na real coordinator: Postgres for the ledger + a leader-election service\n(etcd, Consul) for the leases. That's out of scope for these phases.\nThe schema and module shapes here would need a non-trivial backend\nswap before they could ride on top of either.\n\n<!-- File: src/resources/extensions/gsd/docs/preferences-reference.md (Tokens: ~8583 | Category: anthropic-skill) -->\n# GSD Preferences Reference\n\nFull documentation for `~/.gsd/PREFERENCES.md` (global) and `.gsd/PREFERENCES.md` (project).\n\n---\n\n## Notes\n\n- Keep this skill-first.\n- Prefer explicit skill names or absolute paths.\n- Use absolute paths for personal/local skills when you want zero ambiguity.\n- These preferences guide which skills GSD should load and follow; they do not override higher-priority instructions in the current conversation.\n- For Claude marketplace/plugin import behavior, see `~/.gsd/agent/extensions/gsd/docs/claude-marketplace-import.md`.\n\n---\n\n## Semantics\n\n### Empty Arrays vs Omitted Fields\n\n**Empty arrays (`[]`) are equivalent to omitting the field entirely.** During validation, GSD deletes empty arrays from the preferences object (see `validatePreferences()` in `preferences.ts`):\n\n```typescript\nfor (const key of [\n  \"always_use_skills\",\n  \"prefer_skills\",\n  \"avoid_skills\",\n  \"custom_instructions\",\n] as const) {\n  if (validated[key] && validated[key]!.length === 0) {\n    delete validated[key];\n  }\n}\n```\n\nThese are functionally identical:\n\n```yaml\n# Explicit empty arrays — will be normalized away\nprefer_skills: []\navoid_skills: []\nskill_rules: []\n\n# Omitted entirely — same result\n# (just don't write these fields)\n```\n\n**Recommendation:** Omit fields you don't need. Empty arrays add noise with no effect.\n\n### Global vs Project Preferences\n\nPreferences are loaded from two locations and merged:\n\n1. **Global:** `~/.gsd/PREFERENCES.md` — applies to all projects\n2. **Project:** `.gsd/PREFERENCES.md` — applies to the current project only\n\n**Merge behavior** (see `mergePreferences()` in `preferences.ts`):\n\n- **Scalar fields** (`skill_discovery`, `budget_ceiling`, etc.): Project wins if defined, otherwise global. Uses nullish coalescing (`??`).\n- **Array fields** (`always_use_skills`, `prefer_skills`, etc.): Concatenated via `mergeStringLists()` (global first, then project).\n- **Object fields** (`models`, `git`, `auto_supervisor`): Shallow merge via spread operator `{ ...base, ...override }`.\n\nFor `models`, project settings override global at the phase level. If global has `planning: opus` and project has `planning: sonnet`, the project wins. But if project omits `research`, global's `research` setting is preserved.\n\n### Skill Discovery vs Skill Preferences\n\nThese are **separate concerns**:\n\n| Field                                                | What it controls                                          | Code reference                                           |\n| ---------------------------------------------------- | --------------------------------------------------------- | -------------------------------------------------------- |\n| `skill_discovery`                                    | **Whether** GSD looks for relevant skills during research | `resolveSkillDiscoveryMode()` in `preferences.ts`        |\n| `always_use_skills`, `prefer_skills`, `avoid_skills` | **Which** skills to use when they're found relevant       | `renderPreferencesForSystemPrompt()` in `preferences.ts` |\n\nSetting `prefer_skills: []` does **not** disable skill discovery — it just means you have no preference overrides. Use `skill_discovery: off` to disable discovery entirely.\n\n---\n\n## Field Guide\n\n- `version`: schema version. Start at `1`.\n\n- `mode`: workflow mode — `\"solo\"` or `\"team\"`. Sets sensible defaults for git and project settings based on your workflow. Mode defaults are the lowest priority layer — any explicit preference overrides them. Omit to configure everything manually.\n\n  | Setting                | `solo`       | `team`       |\n  | ---------------------- | ------------ | ------------ |\n  | `git.auto_push`        | `true`       | `false`      |\n  | `git.push_branches`    | `false`      | `true`       |\n  | `git.pre_merge_check`  | `false`      | `true`       |\n  | `git.merge_strategy`   | `\"squash\"`   | `\"squash\"`   |\n  | `git.isolation`        | `\"none\"`     | `\"none\"`     |\n  | `unique_milestone_ids` | `false`      | `true`       |\n\n  Quick setup: `/gsd mode` (global) or `/gsd mode project` (project-level).\n\n- `always_use_skills`: skills GSD should use whenever they are relevant.\n\n- `prefer_skills`: soft defaults GSD should prefer when relevant.\n\n- `avoid_skills`: skills GSD should avoid unless clearly needed.\n\n- `skill_rules`: situational rules with a human-readable `when` trigger and one or more of `use`, `prefer`, or `avoid`.\n\n- `custom_instructions`: extra durable instructions related to skill use. For operational project knowledge, use `.gsd/KNOWLEDGE.md` instead. Rules are file-canonical; patterns and lessons are persisted to the `memories` table and projected back into `KNOWLEDGE.md` on the next session start.\n\n- `language`: preferred response language for all GSD interactions. Accepts any language name or code — `\"Chinese\"`, `\"zh\"`, `\"German\"`, `\"de\"`, `\"日本語\"`, etc. When set, GSD injects \"Always respond in \\<language\\>\" into every agent's system prompt, including after `/clear`. Quickest way to set it: `/gsd language <name>`. To clear: `/gsd language off`.\n\n- `models`: per-stage model selection (applies to both auto-mode and guided-flow dispatches). Keys: `research`, `planning`, `discuss`, `execution`, `execution_simple`, `completion`, `validation`, `subagent`. Values can be:\n  - Simple string: `\"claude-sonnet-4-6\"` — single model, no fallbacks\n  - Provider-qualified string: `\"bedrock/claude-sonnet-4-6\"` — targets a specific provider when the same model ID exists across multiple providers\n  - Object with fallbacks: `{ model: \"claude-opus-4-6\", fallbacks: [\"glm-5\", \"minimax-m2.5\"] }` — tries fallbacks in order if primary fails\n  - Object with provider: `{ model: \"claude-opus-4-6\", provider: \"bedrock\" }` — explicit provider targeting in object format\n  - Omit a key to use whatever model is currently active (except `discuss` and `validation` which fall back to `planning` when unset). Fallbacks are tried when model switching fails (provider unavailable, rate limited, etc.).\n  - `discuss` — used for milestone/slice discussion (interactive context gathering). Falls back to `planning` if unset.\n  - `validation` — used for gate evaluation, roadmap reassessment, milestone validation, and doc rewrites. Falls back to `planning` if unset.\n\n- `skill_staleness_days`: number — skills unused for this many days get deprioritized during discovery. Set to `0` to disable staleness tracking. Default: `60`.\n\n- `skill_discovery`: controls how GSD discovers and applies skills during auto-mode. Valid values:\n  - `auto` — skills are found and applied automatically without prompting.\n  - `suggest` — (default) skills are identified during research but not installed automatically.\n  - `off` — skill discovery is disabled entirely.\n\n- `auto_supervisor`: configures the auto-mode supervisor that monitors agent progress and enforces timeouts. Keys:\n  - `model`: model ID to use for the supervisor process (defaults to the currently active model).\n  - `soft_timeout_minutes`: minutes before the supervisor issues a soft warning (default: 20).\n  - `idle_timeout_minutes`: minutes of inactivity before the supervisor intervenes (default: 10).\n  - `hard_timeout_minutes`: minutes before the supervisor forces termination (default: 30).\n\n- `min_request_interval_ms`: number — minimum integer milliseconds between auto-mode LLM request dispatches. Non-integer values are rounded down (e.g., `1000.9 → 1000`). Use this to proactively slow auto-mode on rate-limited providers and reduce 429 errors. Set to `0` to disable. Default: `0` (disabled).\n\n- `git`: configures GSD's git behavior. All fields are optional — omit any to use defaults. Keys:\n  - `auto_push`: boolean — automatically push commits to the remote after committing. Default: `false`.\n  - `push_branches`: boolean — push the milestone branch to the remote after commits. Default: `false`.\n  - `remote`: string — git remote name to push to. Default: `\"origin\"`.\n  - `snapshots`: boolean — create WIP snapshot commits (e.g. pre-dispatch and stale-uncommitted-changes safety commits emitted by the doctor). Set to `false` to suppress all doctor-initiated `gsd snapshot:` commits. Default: `true`.\n  - `pre_merge_check`: boolean or `\"auto\"` — run pre-merge checks before merging a worktree back to the integration branch. `true` always runs, `false` never runs, `\"auto\"` runs when CI is detected. Default: `\"auto\"`.\n  - `commit_type`: string — override the conventional commit type prefix. Must be one of: `feat`, `fix`, `refactor`, `docs`, `test`, `chore`, `perf`, `ci`, `build`, `style`. Default: inferred from diff content.\n  - `main_branch`: string — the primary branch name for new git repos (e.g., `\"main\"`, `\"master\"`, `\"trunk\"`). Also used by `getMainBranch()` as the preferred branch when auto-detection is ambiguous. Default: `\"main\"`.\n  - `merge_strategy`: `\"squash\"` or `\"merge\"` — controls how worktree branches are merged back. `\"squash\"` combines all commits into one; `\"merge\"` preserves individual commits. Default: `\"squash\"`.\n  - `isolation`: `\"none\"`, `\"worktree\"`, or `\"branch\"` — controls auto-mode git isolation strategy. `\"none\"` works directly on the current branch with no worktree or milestone branch (default, ideal for step-mode with hot reloads); `\"worktree\"` creates a milestone worktree for isolated work; `\"branch\"` works directly in the project root but creates a milestone branch (useful for submodule-heavy repos). `worktree` requires a committed `HEAD`; in a zero-commit repo, GSD temporarily treats it as `none` until the first commit exists. Default: `\"none\"`.\n  - `manage_gitignore`: boolean — when `false`, GSD will not touch `.gitignore` at all. Useful when your project has a strictly managed `.gitignore` and you don't want GSD adding entries. Default: `true`.\n  - `worktree_post_create`: string — script to run after a worktree is created (both auto-mode and manual `/worktree`). Receives `SOURCE_DIR` and `WORKTREE_DIR` as environment variables. Can be absolute or relative to project root. Runs with 30-second timeout. Failure is non-fatal (logged as warning). Default: none.\n  - `auto_pr`: boolean — automatically create a GitHub pull request after a milestone branch is merged. Requires `gh` CLI to be installed. Default: `false`.\n  - `pr_target_branch`: string — branch to target when `auto_pr` is enabled. Defaults to `main_branch` when omitted.\n  - **Deprecated:** `commit_docs` — no longer valid; `.gsd/` is always gitignored. Remove this setting.\n  - **Deprecated:** `merge_to_main` — no longer valid; milestone-level merge is always used. Remove this setting.\n\n- `workspace`: configures multi-repository parent workspaces. Keys:\n  - `mode`: `\"project\"` (default single-repo behavior) or `\"parent\"` (one `.gsd` controlling child repos).\n  - `repositories`: object map of repository IDs to config.\n    - Repository ID format: `^[A-Za-z0-9][A-Za-z0-9._-]*$`.\n    - Reserved ID: `project` is implicit and always maps to the project root; user-defined `workspace.repositories.project` is rejected.\n    - `path`: required relative path that must resolve within the project root (paths escaping via `..` are rejected).\n    - `role`: optional short description of what the repo owns.\n    - `verification`: optional array of verification commands for that repo.\n    - `commit_policy`: optional `\"auto\"` or `\"skip\"` to include or skip commit actions per repo.\n\n## Workspace Example\n\n```yaml\n---\nversion: 1\nworkspace:\n  mode: parent\n  repositories:\n    frontend:\n      path: frontend\n      role: web UI\n      verification:\n        - npm test\n        - npm run lint\n      commit_policy: auto\n    backend:\n      path: ./backend\n      role: API server\n      verification:\n        - go test ./...\n      commit_policy: auto\n---\n```\n\nThis config sets a parent workspace with two child repositories. The implicit `project` repository is always created for the project root and cannot be user-defined.\n\n- `unique_milestone_ids`: boolean — when `true`, generates milestone IDs in `M{seq}-{rand6}` format (e.g. `M001-eh88as`) instead of plain sequential `M001`. Prevents ID collisions in team workflows where multiple contributors create milestones concurrently. Both formats coexist — existing `M001`-style milestones remain valid. Default: `false`.\n\n- `budget_ceiling`: number — maximum dollar amount to spend on auto-mode. When reached, behavior is controlled by `budget_enforcement`. Default: no limit.\n\n- `budget_enforcement`: `\"warn\"`, `\"pause\"`, or `\"halt\"` — action taken when `budget_ceiling` is reached.\n  - `warn` — log a warning but continue execution.\n  - `pause` — pause auto-mode and wait for user confirmation.\n  - `halt` — stop auto-mode immediately.\n  - Default: `\"pause\"`.\n\n- `context_pause_threshold`: number (`0` or `1-100`) — live context window usage percentage at which auto-mode should pause to suggest checkpointing. Set to `0` to disable. Use whole percentages like `75`, not fractional ratios like `0.75`. Default: `0` (disabled).\n\n- `token_profile`: `\"budget\"`, `\"balanced\"`, `\"quality\"`, or `\"burn-max\"` — coordinates model selection, phase skipping, and context compression. `budget` skips research/reassessment and uses cheaper models; `balanced` (default) skips research/reassessment to reduce token burn; `quality` prefers higher-quality models; `burn-max` keeps full-context defaults, disables downgrade routing, and keeps phase skips off.\n\n- `planning_depth`: `\"light\"` or `\"deep\"` — controls project-level discovery before milestone planning. `\"light\"` is the default milestone discussion flow. `\"deep\"` runs workflow preferences, project discussion, requirements discussion, a research-decision gate, and optional project research before milestone planning. Enable it with `/gsd new-project --deep`, `/gsd new-milestone --deep`, or by setting `planning_depth: deep` in project-local `.gsd/PREFERENCES.md`. Global `~/.gsd/PREFERENCES.md` does not opt every fresh repo into deep mode. Deep mode writes `.gsd/PROJECT.md`, `.gsd/REQUIREMENTS.md`, `.gsd/runtime/research-decision.json`, and, when research is approved, `.gsd/research/STACK.md`, `FEATURES.md`, `ARCHITECTURE.md`, and `PITFALLS.md`.\n\n- `phases`: fine-grained control over which phases run. Usually set by `token_profile`, but can be overridden. Keys:\n  - `skip_research`: boolean — skip milestone-level research. Default: `false`.\n  - `reassess_after_slice`: boolean — run a dedicated roadmap-reassessment unit after each completed slice. Default: `false` (per ADR-003 §4). The plan-slice agent for the next slice performs JIT reassessment via a prompt preamble at zero additional token cost; a dedicated reassess session is opt-in. Set to `true` (e.g. via the `burn-max` profile) if you want the explicit session.\n  - `skip_reassess`: boolean — force-disable roadmap reassessment even if `reassess_after_slice` is enabled. Default: `false`.\n  - `skip_slice_research`: boolean — skip per-slice research. Default: `false`.\n\n- `reactive_execution`: controls automatic parallel task dispatch inside a slice. Reactive execution is enabled by default when omitted; set `enabled: false` to opt out. With default-on behavior, GSD only attempts a reactive batch when at least three ready tasks are available and the task-plan IO graph is non-ambiguous. If you set `enabled: true` explicitly, GSD uses the earlier opt-in threshold of two ready tasks. Keys:\n  - `enabled`: boolean — set `false` to force sequential task execution. Default: `true`.\n  - `max_parallel`: number — maximum tasks to dispatch in one batch, range `1`-`8`. Default: `2`.\n  - `isolation_mode`: `\"same-tree\"` — currently the only supported value.\n  - `subagent_model`: string — optional model override for reactive task subagents. Falls back to the `models.subagent` routing when omitted.\n\n- `remote_questions`: route interactive questions to Slack/Discord for headless auto-mode. Keys:\n  - `channel`: `\"slack\"` or `\"discord\"` — channel type.\n  - `channel_id`: string or number — channel ID.\n  - `timeout_minutes`: number — question timeout in minutes (clamped 1-30).\n  - `poll_interval_seconds`: number — poll interval in seconds (clamped 2-30).\n\n- `notifications`: configures desktop notification behavior during auto-mode. Keys:\n  - `enabled`: boolean — master toggle for all notifications. Default: `true`.\n  - `on_complete`: boolean — notify when a unit completes. Default: `true`.\n  - `on_error`: boolean — notify on errors. Default: `true`.\n  - `on_budget`: boolean — notify when budget thresholds are reached. Default: `true`.\n  - `on_milestone`: boolean — notify when a milestone finishes. Default: `true`.\n  - `on_attention`: boolean — notify when manual attention is needed. Default: `true`.\n  - Terminal auto-loop errors persist an `activity/*-auto-crash-note.json` file with error/session metadata; when available, the error notification includes the crash-note path and instructs resuming with `/gsd auto`.\n\n- `cmux`: configures cmux terminal integration when GSD is running inside a cmux workspace. Keys:\n  - `enabled`: boolean — master toggle for cmux integration. Default: `false`.\n  - `notifications`: boolean — route desktop notifications through cmux. Default: `true` when enabled.\n  - `sidebar`: boolean — publish status, progress, and log metadata to the cmux sidebar. Default: `true` when enabled.\n  - `splits`: boolean — run supported subagent work in visible cmux splits. Default: `false`.\n  - `browser`: boolean — reserve the future browser integration flag. Default: `false`.\n\n- `dynamic_routing`: configures the dynamic model router that adjusts model selection based on task complexity. Keys:\n  - `enabled`: boolean — enable dynamic routing. Default: `false`.\n  - `tier_models`: object — model overrides per complexity tier. Keys: `light`, `standard`, `heavy`. Values are model ID strings.\n  - `escalate_on_failure`: boolean — escalate to a higher-tier model when the current one fails. Default: `true`.\n  - `budget_pressure`: boolean — downgrade model tier when budget is under pressure. Default: `true`.\n  - `cross_provider`: boolean — allow routing across different providers. Default: `true`.\n  - `hooks`: boolean — enable routing hooks. Default: `true`.\n  - `capability_routing`: boolean — enable capability-profile scoring for model selection within a tier. Requires `enabled: true`. Default: `false`.\n\n- `disabled_model_providers`: string[] — provider IDs to hide from model selection and routing (for example `[\"google-gemini-cli\"]`). This only affects model availability (`/model`, auto-model selection, routing); it does not disable tool auth flows like `google_search`.\n\n- `uok`: Unified Orchestration Kernel controls. Keys:\n  - `enabled`: boolean — enable kernel wrappers and contract observers. Default: `true`.\n  - `legacy_fallback.enabled`: boolean — emergency release fallback that forces legacy orchestration behavior even when `uok.enabled` is `true`. Default: `false`.\n    - Runtime override: set `GSD_UOK_FORCE_LEGACY=1` (or `GSD_UOK_LEGACY_FALLBACK=1`) to force legacy behavior for the current process.\n  - `gates.enabled`: boolean — route checks through the unified gate runner and persist `gate_runs`. Default: `true`.\n  - `model_policy.enabled`: boolean — enforce policy filtering before model capability scoring. Default: `true`.\n  - `execution_graph.enabled`: boolean — enable DAG scheduler facade/adapters for execution. Default: `true`.\n  - `gitops.enabled`: boolean — persist turn-level git transaction records. Default: `true`.\n  - `gitops.turn_action`: `\"commit\"` | `\"snapshot\"` | `\"status-only\"` — turn transaction mode. Default: `\"commit\"` (per-task atomic commits).\n  - `gitops.turn_push`: boolean — whether turn transactions should include push intent metadata. Default: `false`.\n  - `audit_unified.enabled`: boolean — dual-write unified audit envelope events. Default: `true`.\n  - `plan_v2.enabled`: boolean — enable bounded clarify/research/draft/compile planning flow. Default: `true`.\n\n- `context_management`: configures context hygiene for auto-mode sessions. Keys:\n  - `observation_masking`: boolean — mask old tool results to reduce context bloat. Default: `true`.\n  - `observation_mask_turns`: number — keep this many recent turns verbatim (1-50). Default: `8`.\n  - `compaction_threshold_percent`: number — trigger compaction at this % of context window (0.5-0.95). Lower values fire compaction earlier, reducing drift. Default: `0.60`.\n  - `tool_result_max_chars`: number — max chars per tool result in GSD sessions (200-10000). Default: `800`.\n\n- `auto_visualize`: boolean — show a visualizer hint after each milestone completion in auto-mode. Default: `false`.\n\n- `auto_report`: boolean — generate an HTML report snapshot after each milestone completion. Default: `true`.\n\n- `search_provider`: `\"brave\"`, `\"tavily\"`, `\"ollama\"`, `\"native\"`, or `\"auto\"` — selects the search backend for research phases. `\"native\"` forces Anthropic's built-in web search only; provider values force that backend and disable native search; `\"auto\"` uses the default heuristic. Default: `\"auto\"`.\n\n- `context_selection`: `\"full\"` or `\"smart\"` — controls how files are inlined into context. `\"full\"` inlines entire files; `\"smart\"` uses semantic chunking to include only the most relevant sections. Default is derived from `token_profile`.\n\n- `parallel`: configures parallel orchestration for running multiple slices concurrently. Keys:\n  - `enabled`: boolean — enable parallel execution. Default: `false`.\n  - `max_workers`: number — maximum concurrent workers (1-4). Default: `2`.\n  - `budget_ceiling`: number — optional per-parallel-run budget ceiling.\n  - `merge_strategy`: `\"per-slice\"` or `\"per-milestone\"` — when to merge worktree results back. Default: `\"per-milestone\"`.\n  - `auto_merge`: `\"auto\"`, `\"confirm\"`, or `\"manual\"` — merge behavior after completion. `\"auto\"` merges immediately; `\"confirm\"` asks first; `\"manual\"` leaves branches for you. Default: `\"confirm\"`.\n  - `worker_model`: string — optional model override for parallel milestone workers. When set, workers use this model (e.g. `\"claude-haiku-4-5\"`) instead of inheriting the coordinator's model. Useful for cost savings on execution-heavy milestones.\n\n- `workspace`: repository-scoping for parent/multi-repo workspaces. Keys:\n  - `mode`: `\"project\"` | `\"parent\"` — enables single-repo (default) or parent workspace behavior.\n  - `repositories`: map of repository IDs to repository config:\n    - `path`: string (required) — path relative to project root.\n    - `role`: string (optional) — informational role label.\n    - `verification`: string[] (optional) — repository-specific verification commands used when global `verification_commands` is not set.\n    - `commit_policy`: `\"auto\"` | `\"skip\"` (optional) — per-repository closeout commit behavior.\n  - `project` is always an implicit repository target mapped to the project root for backward compatibility.\n  - Plan/task `targetRepositories` defaults to `[\"project\"]` when omitted.\n\n- `verification_commands`: string[] — shell commands to run as verification after task execution (e.g., `[\"npm test\", \"npm run lint\"]`). Commands run in order; if any fails, the task is marked as needing fixes.\n\n- `verification_auto_fix`: boolean — when `true`, automatically attempt to fix verification failures instead of just reporting them. Default: `false`.\n\n- `verification_max_retries`: number — maximum number of fix-and-retry cycles for verification failures. Default: `0` (no retries).\n\n- `per_unit_cost_cap_usd`: number — per-unit retry cost ceiling in USD for verification retries. Must be a positive finite number when set; invalid values are rejected during preference validation. Default: `5.0`. During auto-verification and artifact-retry flows, auto-mode pauses when the current unit reaches this cap or when current unit cost spikes to at least `3.0x` the rolling average.\n\n- `uat_dispatch`: boolean — when `true`, enables UAT (User Acceptance Testing) dispatch mode. Default: `false`.\n\n- `post_unit_hooks`: array — hooks that fire after a unit completes. Each entry has:\n  - `name`: string — unique hook identifier.\n  - `after`: string[] — unit types that trigger this hook (e.g., `[\"execute-task\"]`).\n  - `prompt`: string — prompt sent to the LLM. Supports `{milestoneId}`, `{sliceId}`, `{taskId}` substitutions.\n  - `max_cycles`: number — max times this hook fires per trigger (default: 1, max: 10).\n  - `model`: string — optional model override.\n  - `artifact`: string — expected output file name (relative to task/slice dir). Hook is skipped if file already exists (idempotent).\n  - `retry_on`: string — if this file is produced instead of the artifact, re-run the trigger unit then re-run hooks.\n  - `agent`: string — agent definition file to use for hook execution.\n  - `enabled`: boolean — toggle without removing (default: `true`).\n\n- `pre_dispatch_hooks`: array — hooks that fire before a unit is dispatched. Each entry has:\n  - `name`: string — unique hook identifier.\n  - `before`: string[] — unit types to intercept.\n  - `action`: `\"modify\"`, `\"skip\"`, or `\"replace\"` — what to do with the unit.\n  - `prepend`: string — text prepended to unit prompt (for `\"modify\"` action).\n  - `append`: string — text appended to unit prompt (for `\"modify\"` action).\n  - `prompt`: string — replacement prompt (for `\"replace\"` action; required when action is `\"replace\"`).\n  - `unit_type`: string — override unit type label (for `\"replace\"` action).\n  - `skip_if`: string — for `\"skip\"` action: only skip if this file exists (relative to unit dir).\n  - `model`: string — optional model override when this hook fires.\n  - `enabled`: boolean — toggle without removing (default: `true`).\n\n  **Action validation:**\n  - `\"modify\"` requires at least one of `prepend` or `append`.\n  - `\"replace\"` requires `prompt`.\n  - `\"skip\"` is valid with no additional fields.\n\n  **Known unit types for `before`/`after`:** `research-milestone`, `plan-milestone`, `research-slice`, `plan-slice`, `execute-task`, `complete-slice`, `replan-slice`, `reassess-roadmap`, `run-uat`.\n\n- `experimental`: opt-in experimental features. All features here are **off by default** — you must explicitly set each one to `true` to enable it. Features in this block may change or be removed without a deprecation cycle while in experimental status. Keys:\n  - `rtk`: boolean — enable RTK (Real-Time Kompression) shell-command compression. When enabled, GSD wraps shell commands through the RTK binary to reduce token usage during command execution. RTK is downloaded automatically on first use if not already installed. **Default: `false`** (opt-in required). Set `GSD_RTK_DISABLED=1` in the environment to force-disable regardless of this preference.\n\n---\n\n## Best Practices\n\n- Keep `always_use_skills` short.\n- Use `skill_rules` for situational routing, not broad personality preferences.\n- Prefer skill names for stable built-in skills.\n- Prefer absolute paths for local personal skills.\n- **Omit fields you don't need** — empty arrays add noise with no effect.\n\n---\n\n## Workflow Mode Examples\n\n**Solo developer — auto-push, simple IDs:**\n\n```yaml\n---\nversion: 1\nmode: solo\n---\n```\n\nEquivalent to setting `git.auto_push: true`, `git.push_branches: false`, `git.pre_merge_check: false`, `git.merge_strategy: squash`, `git.isolation: none`, `unique_milestone_ids: false`.\n\n**Team — unique IDs, push branches, pre-merge checks:**\n\n```yaml\n---\nversion: 1\nmode: team\n---\n```\n\nEquivalent to setting `git.auto_push: false`, `git.push_branches: true`, `git.pre_merge_check: true`, `git.merge_strategy: squash`, `git.isolation: none`, `unique_milestone_ids: true`.\n\n**Mode with overrides — team mode but with auto-push:**\n\n```yaml\n---\nversion: 1\nmode: team\ngit:\n  auto_push: true\n---\n```\n\nGets all team defaults except `auto_push`, which is explicitly overridden to `true`. Any explicit setting always wins over the mode default.\n\n---\n\n## Minimal Example\n\nThe cleanest preferences file only specifies what you actually want:\n\n```yaml\n---\nversion: 1\nalways_use_skills:\n  - debug-like-expert\nskill_discovery: suggest\nmodels:\n  planning: claude-opus-4-6\n  execution: claude-sonnet-4-6\n---\n```\n\nEverything else uses defaults. No `prefer_skills: []`, no `avoid_skills: []`, no `auto_supervisor: {}` — those are just noise.\n\n---\n\n## Models Example\n\n```yaml\n---\nversion: 1\nmodels:\n  research: claude-sonnet-4-6\n  planning: claude-opus-4-6\n  execution: claude-sonnet-4-6\n  completion: claude-sonnet-4-6\n---\n```\n\nOpus for planning (where architectural decisions matter most), Sonnet for everything else (faster, cheaper). Omit any key to use the currently selected model.\n\n## Models with Fallbacks Example\n\n```yaml\n---\nversion: 1\nmodels:\n  research:\n    model: openrouter/deepseek/deepseek-r1\n    fallbacks:\n      - openrouter/minimax/minimax-m2.5\n  planning:\n    model: claude-opus-4-6\n    fallbacks:\n      - openrouter/z-ai/glm-5\n      - openrouter/moonshotai/kimi-k2.5\n  execution:\n    model: openrouter/z-ai/glm-5\n    fallbacks:\n      - openrouter/minimax/minimax-m2.5\n  completion: openrouter/minimax/minimax-m2.5\n---\n```\n\nWhen a model fails to switch (provider unavailable, rate limited, credits exhausted), GSD automatically tries the next model in the `fallbacks` list. This ensures auto-mode continues even when your preferred provider hits limits.\n\n## Provider Targeting\n\nWhen the same model ID exists across multiple providers (e.g., `claude-sonnet-4-6` on both Anthropic and Bedrock), use the `provider/model` format or the `provider` field to target a specific one:\n\n```yaml\n---\nversion: 1\nmodels:\n  # String format: provider/model\n  research: bedrock/claude-sonnet-4-6\n  planning: anthropic/claude-opus-4-6\n\n  # Object format: explicit provider field\n  execution:\n    model: claude-sonnet-4-6\n    provider: bedrock\n    fallbacks:\n      - anthropic/claude-sonnet-4-6\n---\n```\n\nIf you use a bare model ID (no provider prefix) and it exists in multiple providers, GSD will warn you and resolve to the first available match. Use `provider/model` format to avoid ambiguity.\n\n**Cost-optimized example** — use cheap models with expensive ones as fallback for critical phases:\n\n```yaml\n---\nversion: 1\nmodels:\n  research: openrouter/deepseek/deepseek-r1 # $0.28/$0.42 per 1M tokens\n  planning:\n    model: claude-opus-4-6 # $5/$25 — best for architecture\n    fallbacks:\n      - openrouter/z-ai/glm-5 # $1/$3.20 — strong alternative\n  execution: openrouter/minimax/minimax-m2.5 # $0.30/$1.20 — cheapest quality\n  completion: openrouter/minimax/minimax-m2.5\n---\n```\n\n---\n\n## Example Variations\n\n**Minimal — always load a UAT skill and route Clerk tasks:**\n\n```yaml\n---\nversion: 1\nalways_use_skills:\n  - /Users/you/.claude/skills/verify-uat\nskill_rules:\n  - when: finishing implementation and human judgment matters\n    use:\n      - /Users/you/.claude/skills/verify-uat\n---\n```\n\n**Richer routing — prefer cleanup and authentication skills:**\n\n```yaml\n---\nversion: 1\nprefer_skills:\n  - commit-ignore\nskill_rules:\n  - when: task involves Clerk authentication\n    use:\n      - clerk\n      - clerk-setup\n  - when: the user is looking for installable capability rather than implementation\n    prefer:\n      - find-skills\n---\n```\n\n---\n\n## Git Preferences Example\n\n```yaml\n---\nversion: 1\ngit:\n  auto_push: true\n  push_branches: true\n  remote: origin\n  snapshots: true\n  pre_merge_check: auto\n  commit_type: feat\n---\n```\n\nAll git fields are optional. Omit any field to use the default behavior. Project-level preferences override global preferences on a per-field basis.\n\n---\n\n## Budget & Cost Control Example\n\n```yaml\n---\nversion: 1\nbudget_ceiling: 10.00\nbudget_enforcement: pause\ncontext_pause_threshold: 80\n---\n```\n\nSets a $10 budget ceiling. Auto-mode pauses when the ceiling is reached. Context window pauses at 80% usage for checkpointing.\n\n---\n\n## Notifications Example\n\n```yaml\n---\nversion: 1\nnotifications:\n  enabled: true\n  on_complete: false\n  on_error: true\n  on_budget: true\n  on_milestone: true\n  on_attention: true\n---\n```\n\nDisables per-unit completion notifications (noisy in long runs) while keeping error, budget, milestone, and attention notifications enabled.\n\n---\n\n## cmux Example\n\n```yaml\n---\nversion: 1\ncmux:\n  enabled: true\n  notifications: true\n  sidebar: true\n  splits: true\n  browser: false\n---\n```\n\nEnables cmux-aware notifications, sidebar metadata, and visible subagent splits when GSD is running inside a cmux terminal.\n\n---\n\n## Post-Unit Hooks Example\n\n```yaml\n---\nversion: 1\npost_unit_hooks:\n  - name: code-review\n    after:\n      - execute-task\n    prompt: \"Review the code changes in {sliceId}/{taskId} for quality, security, and test coverage.\"\n    max_cycles: 1\n    artifact: REVIEW.md\n---\n```\n\nRuns an automated code review after each task execution. Skips if `REVIEW.md` already exists (idempotent).\n\n---\n\n## Pre-Dispatch Hooks Examples\n\n**Modify — inject instructions before every task:**\n\n```yaml\n---\nversion: 1\npre_dispatch_hooks:\n  - name: enforce-standards\n    before:\n      - execute-task\n    action: modify\n    prepend: \"Follow our TypeScript coding standards and always run linting.\"\n---\n```\n\n**Skip — skip per-slice research when a research file already exists:**\n\n```yaml\n---\nversion: 1\npre_dispatch_hooks:\n  - name: skip-existing-research\n    before:\n      - research-slice\n    action: skip\n    skip_if: RESEARCH.md\n---\n```\n\n**Replace — substitute a custom prompt for task execution:**\n\n```yaml\n---\nversion: 1\npre_dispatch_hooks:\n  - name: tdd-execute\n    before:\n      - execute-task\n    action: replace\n    prompt: \"Implement the task using strict TDD. Write failing tests first, then implement, then refactor.\"\n    model: claude-opus-4-6\n---\n```\n\n---\n\n## Token Profile & Phases Example\n\n```yaml\n---\nversion: 1\ntoken_profile: budget\nphases:\n  skip_research: true\n  skip_reassess: true\n  skip_slice_research: false\n---\n```\n\nUses the `budget` profile to minimize token usage, with explicit override to keep slice-level research enabled.\n\n---\n\n## Remote Questions Example\n\n```yaml\n---\nversion: 1\nremote_questions:\n  channel: slack\n  channel_id: \"C0123456789\"\n  timeout_minutes: 15\n  poll_interval_seconds: 10\n---\n```\n\nRoutes interactive questions to a Slack channel for headless auto-mode sessions. Questions time out after 15 minutes if unanswered.\n\n---\n\n## Dynamic Routing Example\n\n```yaml\n---\nversion: 1\ndynamic_routing:\n  enabled: true\n  tier_models:\n    light: openrouter/minimax/minimax-m2.5\n    standard: claude-sonnet-4-6\n    heavy: claude-opus-4-6\n  escalate_on_failure: true\n  budget_pressure: true\n---\n```\n\nAutomatically selects model tier based on task complexity. Simple tasks use the `light` model, complex tasks escalate to `heavy`. Under budget pressure, tasks are routed to cheaper tiers.\n\n---\n\n## Parallel Execution Example\n\n```yaml\n---\nversion: 1\nparallel:\n  enabled: true\n  max_workers: 3\n  merge_strategy: per-milestone\n  auto_merge: confirm\n---\n```\n\nRuns up to 3 slices concurrently in separate worktrees. Results are merged per-milestone with user confirmation.\n\n---\n\n## Verification Example\n\n```yaml\n---\nversion: 1\nverification_commands:\n  - npm test\n  - npm run lint\n  - npm run typecheck\nverification_auto_fix: true\nverification_max_retries: 2\n---\n```\n\nRuns test, lint, and typecheck after each task. On failure, auto-fix is attempted up to 2 times before reporting the issue.\n\n## Experimental Features Example\n\n```yaml\n---\nversion: 1\nexperimental:\n  rtk: true\n---\n```\n\nOpts in to RTK shell-command compression. RTK is downloaded automatically on first use. Set `GSD_RTK_DISABLED=1` to force-disable at the environment level regardless of this setting.\n\n<!-- File: src/resources/extensions/gsd/prompts/heal-skill.md (Tokens: ~574 | Category: anthropic-skill) -->\n## Skill Heal Analysis\n\nAnalyze the just-completed unit ({{unitId}}) for skill drift.\n\n### Steps\n\n1. **Identify loaded skill**: Check which SKILL.md file was read during this unit by examining recent tool calls. If no skill was explicitly loaded (no `read` call to a SKILL.md path), write \"No skill loaded — skipping heal analysis\" to {{healArtifact}} and stop.\n\n2. **Read the skill**: Load the SKILL.md that was used during this unit.\n\n3. **Compare execution to skill guidance**: Review what the agent actually did vs what the skill recommended. Look for:\n   - API patterns the skill recommended that the agent did differently\n   - Error handling approaches the skill specified but the agent bypassed\n   - Conventions the skill documented that the agent ignored\n   - Outdated instructions in the skill that caused errors, retries, or workarounds\n   - Commands or tools the skill referenced that no longer exist or have changed\n\n4. **Assess drift severity**:\n   - **None**: Agent followed skill correctly → write \"No drift detected\" to {{healArtifact}} and stop\n   - **Minor**: Agent found a better approach but skill isn't wrong → append a note to `.gsd/KNOWLEDGE.md` and stop\n   - **Significant**: Skill has outdated or incorrect guidance → continue to step 5\n\n5. **If significant drift found**, append a heal suggestion to `.gsd/skill-review-queue.md`:\n\n```markdown\n### {{skillName}} (flagged {{date}})\n- **Unit:** {{unitId}}\n- **Issue:** {1-2 sentence description of what was wrong}\n- **Root cause:** {outdated API / incorrect pattern / missing context / etc.}\n- **Discovery method:** {how the agent discovered the skill was wrong — error message, trial and error, docs lookup, etc.}\n- **Proposed fix:**\n  - File: {relative path to the file in the skill directory}\n  - Section: {section heading or line range}\n  - Current: {quote the incorrect/outdated text}\n  - Suggested: {the corrected text}\n- **Action:** [ ] Reviewed [ ] Updated [ ] Dismissed\n```\n\nThen write a brief summary of the finding to {{healArtifact}}.\n\n**Critical rules:**\n- Do NOT modify any skill files directly. Only write to the review queue.\n- The SkillsBench research (Feb 2026) shows curated skills beat auto-generated ones by +16.2pp. Human review is what makes this valuable.\n- Keep the analysis focused — don't flag stylistic preferences, only genuine errors or outdated content.\n- If multiple issues found, write one entry per issue.\n\n<!-- File: src/resources/extensions/gsd/prompts/system.md (Tokens: ~3080 | Category: anthropic-skill) -->\n## GSD - Get Shit Done\n\nYou are GSD - a craftsman-engineer who co-owns the project.\n\nOperating posture:\n\n- Measure twice; care through clear choices and correct details.\n- Be warm but terse. State uncertainty, tradeoffs, problems, and progress plainly.\n- In discussion/planning, flag risks, push back when needed, then respect the user's decision.\n- In execution, trust the accepted plan; surface only genuinely plan-invalidating issues through blockers.\n- Work pragmatically with existing code and tech debt.\n- Write secure, performant, complete code without gold-plating, TODO stubs, fake implementations, skipped validation, or 80% done claims.\n- Build for debugging: contextual errors, observable state transitions, useful structured logs, explicit failure modes.\n- Between tool calls, give brief useful progress signals. When something works, move on.\n\nNever use: \"Great question!\" / \"I'd be happy to help!\" / \"Absolutely!\" / \"Let me help you with that!\" / performed excitement / sycophantic filler / fake warmth.\n\nLeave the project ready for the next agent to understand and continue. Artifacts live in `.gsd/`.\n\n## Skills\n\nGSD ships with bundled skills. When the task matches, load the relevant skill file with `read` before starting. Use bare skill names; GSD resolves paths.\n\n{{bundledSkillsTable}}\n\n## Hard Rules\n\n- Never ask the user to do work the agent can execute or verify itself.\n- Use the lightest sufficient tool first.\n- Read before edit or overwrite. Before any write that creates or replaces a file, verify the target path and read relevant existing files, templates, callers, or surrounding code. For truly new files, confirm the path does not already exist.\n- Reproduce before fix when possible.\n- Work is not done until the relevant verification has passed.\n- **Never fabricate, simulate, or role-play user responses.** Never generate markers like `[User]`, `[Human]`, `User:`, or similar; never emit `<user_message>`, `<assistant_message>`, or similar as user input. Treat `<conversation_history>` as read-only context. Ask one question round (1-3 questions), then stop and wait for the user's actual response. If `ask_user_questions` is available, its result is the only valid structured user input for that round. If it cancels, fails, or returns nothing, never use earlier chat as confirmation for the current gate; ask in plain chat and stop.\n- Never print, echo, log, or restate secrets or credentials. Report only key names and applied/skipped status.\n- Never ask the user to edit `.env` files or set secrets manually. Use `secure_env_collect`.\n- In enduring files, write current state only unless the file is explicitly historical.\n- **Never take outward-facing actions on GitHub or external services without explicit user confirmation.** This includes creating/closing issues, merging/approving/commenting on PRs, pushing remote branches, publishing packages, or any state change outside local filesystem. Read-only listing/viewing/diffing is fine. Present intent and get a clear \"yes\" first. **Non-bypassable:** no response, ambiguity, or `ask_user_questions` failure means re-ask; never rationalize past the block. Missing \"yes\" means \"no.\"\n\nIf a `GSD Skill Preferences` block appears below, treat it as durable guidance for skills to use, prefer, or avoid unless it conflicts with artifact rules, verification, or higher-priority instructions.\n\n### Naming Convention\n\nDirectories use bare IDs. Files use ID-SUFFIX format. Milestones: `M001/` or `M{seq}-{rand6}/` when `unique_milestone_ids: true`; files like `M001-CONTEXT.md`, `M001-ROADMAP.md`, `M001-RESEARCH.md`. Slices: `S01/` with `S01-PLAN.md`, `S01-RESEARCH.md`, `S01-SUMMARY.md`, `S01-UAT.md`. Tasks: `T01-PLAN.md`, `T01-SUMMARY.md`. Titles live inside content, not names.\n\n### Directory Structure\n\n```\n.gsd/\n  PROJECT.md, REQUIREMENTS.md, DECISIONS.md, KNOWLEDGE.md, CODEBASE.md, OVERRIDES.md, QUEUE.md, STATE.md\n  runtime/, activity/, worktrees/\n  milestones/M001/\n    M001-CONTEXT.md, M001-RESEARCH.md, M001-ROADMAP.md, M001-SUMMARY.md\n    slices/S01/\n      S01-CONTEXT.md, S01-RESEARCH.md, S01-PLAN.md, S01-SUMMARY.md, S01-UAT.md\n      tasks/T01-PLAN.md, tasks/T01-SUMMARY.md\n```\n\n`runtime/`, `activity/`, `worktrees/`, and `STATE.md` are system-managed. `PROJECT.md` is current state; `REQUIREMENTS.md` is the active capability contract; `DECISIONS.md` and `KNOWLEDGE.md` are append-only; `CODEBASE.md` is an auto-refreshed codebase map.\n\n### Isolation Model\n\nAuto-mode isolation is configured in `.gsd/PREFERENCES.md` under `git.isolation`: **none** works on the current branch; **worktree** uses `.gsd/worktrees/<MID>/` on `milestone/<MID>` and merges back on completion; **branch** uses `milestone/<MID>` in-place. Slices commit sequentially on the active branch; no per-slice branches.\n\n**If you are executing in auto-mode, your working directory is shown in the Working Directory section of your prompt.** Use relative paths. Do not navigate to any other copy of the project.\n\n### Conventions\n\n- `PROJECT.md`: living current-state doc, refreshed at slice completion when stale.\n- `REQUIREMENTS.md`: capability contract; requirements move Active/Validated/Deferred/Blocked/Out of Scope as evidence changes.\n- `DECISIONS.md` and `KNOWLEDGE.md`: append-only decision/rule registers.\n- `CODEBASE.md`: generated structural cache. GSD auto-refreshes it when tracked files change and injects it when available. Use `/gsd codebase update` only to force refresh.\n- `CONTEXT.md`: milestone/slice scope, goals, constraints, decisions; authoritative when present.\n- Milestones are phases; slices are demoable increments ordered by risk; tasks are single-context units.\n- Checkboxes are toggled by gsd_* tools, never manually.\n- Summaries compress prior work; read them instead of all task details.\n\n### Artifact Templates\n\nTemplates are in `{{templatesDir}}`.\n\n**Always read the relevant template before writing an artifact.** Parsers depend on exact formatting:\n\n- Roadmap slices: `- [ ] **S01: Title** \\`risk:level\\` \\`depends:[]\\``\n- Plan tasks: `- [ ] **T01: Title** \\`est:estimate\\``\n- Summaries use YAML frontmatter\n\n### Commands\n\n- `/gsd` - contextual wizard\n- `/gsd auto` - auto-execute (fresh context per task)\n- `/gsd stop` - stop auto-mode\n- `/gsd status` - progress dashboard overlay\n- `/gsd queue` - queue future milestones (safe while auto-mode is running)\n- `/gsd quick <task>` - quick task with GSD guarantees (atomic commits, state tracking) but no milestone ceremony\n- `/gsd codebase [generate|update|stats]` - manage the `.gsd/CODEBASE.md` cache used for prompt context\n- `{{shortcutDashboard}}` - toggle dashboard overlay\n- `{{shortcutShell}}` - show shell processes\n\n## Execution Heuristics\n\n### Tool rules\n\n**File reading:** Use `read` for file inspection. Never use `cat`, `head`, `tail`, or `sed -n` to view contents. Use `read` with `offset`/`limit` for slicing. `bash` is for searching (`rg`, `grep`, `find`) and commands, not displaying files.\n\n**File editing:** Always `read` before `edit` or overwrite. Before `write`, confirm whether the path exists; if it does, `read` it first and preserve intentional existing content. Use `write` only for new files or complete rewrites.\n\n**Code navigation:** Use `lsp` for definition, type_definition, implementation, references, calls, hover, signature, symbols, rename, code_actions, format, and diagnostics. Do not `grep` symbol definitions or shell out to formatters when `lsp` can do it. After code edits, run `lsp diagnostics`.\n\n**Codebase exploration:** Use `subagent` with `scout` for broad unfamiliar subsystem mapping, `rg` for text search, and `lsp` for structure. Do not read files one-by-one to explore; search first, then read relevant files.\n\n**Documentation lookup:** Use `resolve_library` -> `get_library_docs` for library/framework questions. Start with `tokens=5000`. Never guess API signatures when docs are available.\n\n**External facts:** Use `search-the-web` + `fetch_page`, or `search_and_read`; use `freshness` for recency. Never state current facts from training data without verification.\n\n**Background processes:** Use `bg_shell` `start` + `wait_for_ready` for servers/watchers/daemons. Never use `bash` with `&` or `nohup`; inherited stdout can hang. Never poll with `sleep`; use `wait_for_ready`. For status use `digest`, `highlights` for significant lines, and `output` only when debugging.\n\n**One-shot commands:** Use `async_bash` for builds, tests, and installs. Results are pushed on exit; use `await_job` only to block on a specific job.\n\n**Stale job hygiene:** After editing source to fix a failure, `cancel_job` every in-flight `async_bash` job before rerunning. Changed inputs make in-flight outputs untrusted.\n\n**Secrets:** Use `secure_env_collect`. Never ask the user to edit `.env` files or paste secrets.\n\n**Browser verification:** Verify frontend work against a running app. Discovery: `browser_find`/`browser_snapshot_refs`. Action: refs/selectors -> `browser_batch`. Verification: `browser_assert`. Diagnostics: `browser_diff` -> console/network logs -> full inspection as last resort. Retry only with a new hypothesis.\n\n### Anti-patterns — never do these\n\n- Never use `cat` to read a file you might edit; use `read`.\n- Never `grep` for a function definition when `lsp` go-to-definition is available.\n- Never poll servers with `sleep` loops; use `bg_shell wait_for_ready`.\n- Never background with `bash` + `&`; use `bg_shell start`.\n- Never use `bg_shell output` for status; use `digest`.\n- Never read files one-by-one to understand a subsystem; use `rg` or `scout` first.\n- Never guess library APIs; use `get_library_docs`.\n- Never ask the user to run/check/set something you can do.\n- Never await stale async jobs after editing source; cancel then re-run.\n- Never query `.gsd/gsd.db` directly via `sqlite3`, `better-sqlite3`, or `node -e require('better-sqlite3')`; the engine owns a single-writer WAL connection. Use `gsd_milestone_status`, `gsd_journal_query`, or other `gsd_*` tools.\n\n### Ask vs infer\n\nAsk only when the answer materially affects the result and cannot be derived from repo evidence, docs, runtime behavior, or command output. If multiple interpretations are reasonable, choose the smallest safe reversible action.\n\n### Code structure and abstraction\n\n- Prefer small primitives over monoliths; extract around real seams.\n- Separate orchestration from implementation.\n- Prefer boring standard abstractions over clever custom frameworks.\n- Do not abstract speculatively; keep code local until the seam stabilizes.\n- Preserve local consistency.\n\n### Verification and definition of done\n\nVerify according to task type: bug fix → rerun repro, script fix → rerun command, UI fix → verify in browser, refactor → run tests, env fix → rerun blocked workflow, file ops → confirm filesystem state, docs → verify paths and commands match reality.\n\nFor non-trivial work, verify both the feature and the failure/diagnostic surface. If a command fails, loop: inspect error, fix, rerun until it passes or a real blocker requires user input.\n\nWork is not done when the code compiles. Work is done when the verification passes.\n\n### Agent-First Observability\n\nFor relevant work: add health/status surfaces, persist failure state (last error, phase, timestamp, retry count), verify both happy path and at least one diagnostic signal. Never log secrets. Remove noisy one-off instrumentation before finishing unless it provides durable diagnostic value.\n\n### Root-cause-first debugging\n\nFix root causes, not symptoms. If applying temporary mitigation, label it and preserve the path to the real fix. Never add guards/try-catch to suppress undiagnosed errors.\n\n## Communication\n\n- All plans are for the agent's own execution, not an imaginary team's. No enterprise patterns unless explicitly asked for.\n- Push back on security issues, performance problems, anti-patterns, and unnecessary complexity with concrete reasoning - especially during discussion and planning.\n- Between tool calls, narrate decisions, discoveries, phase transitions, and verification outcomes in one or two complete sentences. Do not narrate every call or the obvious.\n- State uncertainty plainly: \"Not sure this handles X - testing it.\" No performed confidence, no hedging paragraphs.\n- All user-visible narration must be grammatical English. Do not emit compressed planner notes like \"Need inspect X\". If it fits a commit comment or standup note, it is acceptable.\n- When debugging, stay curious. Problems are puzzles. Say what's interesting about the failure before reaching for fixes.\n- After completing a task, give a brief summary and 2-4 numbered next-step options; last option is always \"Other\". Omit the list for strict output formats.\n\nGood narration: \"Three existing handlers follow a middleware pattern - using that instead of a custom wrapper.\"\nGood narration: \"Tests pass. Running slice-level verification.\"\nGood narration: \"I need the task-plan template first, then I'll compare the existing T01 and T02 plans.\"\nBad narration: \"Reading the file now.\" / \"Let me check this.\" / \"I'll look at the tests next.\"\nBad narration: \"Need create plan artifact likely requires template maybe read existing task plans.\"\n\n<!-- File: src/resources/extensions/gsd/skills/gsd-headless/references/answer-injection.md (Tokens: ~661 | Category: anthropic-skill) -->\n# Answer Injection\n\nPre-supply answers to eliminate interactive prompts during headless execution.\n\n## CLI Usage\n\n```bash\ngsd headless --answers answers.json auto\ngsd headless --answers answers.json new-milestone --context spec.md --auto\n```\n\nThe `--answers` flag takes a path to a JSON file containing pre-supplied answers and secrets.\n\n## Answer File Schema\n\n```json\n{\n  \"questions\": {\n    \"question_id\": \"selected_option_label\",\n    \"multi_select_question\": [\"option_a\", \"option_b\"]\n  },\n  \"secrets\": {\n    \"API_KEY\": \"sk-...\",\n    \"DATABASE_URL\": \"postgres://...\"\n  },\n  \"defaults\": {\n    \"strategy\": \"first_option\"\n  }\n}\n```\n\n### Fields\n\n- **questions**: Map question ID → answer. String for single-select, string[] for multi-select.\n- **secrets**: Map env var name → value. Injected as environment variables into the RPC child process. The child's `checkExistingEnvKeys()` detects them in `process.env` and marks them as \"already set\" — no interactive prompt needed.\n- **defaults.strategy**: Fallback for unmatched questions.\n  - `\"first_option\"` — auto-select first available option (default)\n  - `\"cancel\"` — cancel the request\n\n## Secrets Mechanism\n\nSecrets are injected via the `RpcClient` `env` option, which merges them into the child process's `process.env`. This means:\n\n1. The headless orchestrator reads the answer file\n2. Secret values are passed as `env` to `RpcClient`\n3. The child process spawns with these env vars set\n4. When `secure_env_collect` runs, `checkExistingEnvKeys()` finds the keys already in `process.env`\n5. The tool skips the interactive prompt and reports the keys as \"already configured\"\n\nSecrets are never logged or included in event streams.\n\n## How It Works\n\nTwo-phase correlation:\n1. **Observe** `tool_execution_start` events for `ask_user_questions` — extracts question metadata (ID, options, allowMultiple)\n2. **Match** subsequent `extension_ui_request` events to metadata, respond with pre-supplied answer\n\nHandles out-of-order events (extension_ui_request can arrive before tool_execution_start in RPC mode) via deferred processing queue with 500ms timeout.\n\n## Coexistence with --supervised\n\nBoth `--answers` and `--supervised` can be active simultaneously. Priority order:\n1. Answer injector tries first\n2. If no answer found, supervised mode takes over\n3. If no orchestrator response, auto-responder kicks in after timeout\n\n## Without Answer Injection\n\nHeadless mode has built-in auto-responders:\n- **select** → picks first option\n- **confirm** → auto-confirms\n- **input** → empty string\n- **editor** → returns prefill or empty\n\nAnswer injection overrides these defaults with specific answers when precision matters.\n\n## Diagnostics\n\nThe injector tracks stats printed in the summary:\n- `questionsAnswered` / `questionsDefaulted`\n- `secretsProvided`\n\nUnused question IDs and secret keys are warned about at the end.\n\n<!-- File: src/resources/extensions/gsd/skills/gsd-headless/references/commands.md (Tokens: ~700 | Category: anthropic-skill) -->\n# GSD Commands Reference\n\nAll commands can be run via `gsd headless [command]`.\n\n## Workflow Commands\n\n| Command | Description |\n|---------|-------------|\n| `auto` | Autonomous mode — loop until milestone complete (default) |\n| `next` | Step mode — execute one unit, then exit |\n| `stop` | Stop auto-mode gracefully |\n| `pause` | Pause auto-mode (preserves state, resumable) |\n| `new-milestone` | Create milestone from specification (requires `--context`) |\n| `dispatch <phase>` | Force-dispatch: research, plan, execute, complete, reassess, uat, replan |\n| `discuss` | Start guided milestone/slice discussion |\n\n## State Inspection\n\n| Command | Description |\n|---------|-------------|\n| `query` | **Instant JSON snapshot** — state, next dispatch, parallel costs. No LLM, ~50ms. Recommended for orchestrators. |\n| `status` | Progress dashboard (TUI overlay — useful interactively, not for parsing) |\n| `visualize` | Workflow visualizer (deps, metrics, timeline) |\n| `history` | Execution history (supports --cost, --phase, --model, limit) |\n\n## Unit Control\n\n| Command | Description |\n|---------|-------------|\n| `skip` | Prevent a unit from auto-mode dispatch |\n| `undo` | Revert last completed unit (--force flag) |\n| `steer <desc>` | Hard-steer plan documents during execution |\n| `queue` | Queue and reorder future milestones |\n| `capture` | Fire-and-forget thought capture |\n| `triage` | Manually trigger triage of pending captures |\n\n## Configuration & Health\n\n| Command | Description |\n|---------|-------------|\n| `prefs` | Manage preferences (global/project/status/wizard/setup) |\n| `config` | Set API keys for external tools |\n| `doctor` | Runtime health checks with auto-fix |\n| `hooks` | Show configured post-unit and pre-dispatch hooks |\n| `knowledge <rule\\|pattern\\|lesson>` | Add persistent project knowledge |\n| `cleanup` | Remove merged branches or snapshots |\n| `export` | Export results (--json, --markdown) |\n| `migrate` | Migrate v1 .planning directory to DB-backed .gsd with backup and audit |\n| `remote` | Control remote auto-mode (slack, discord, status, disconnect) |\n| `inspect` | Show SQLite DB diagnostics (schema, row counts) |\n| `forensics` | Post-mortem investigation of auto-mode failures |\n\n## Phases\n\nGSD workflows progress through these phases:\n`pre-planning` → `needs-discussion` → `discussing` → `researching` → `planning` → `executing` → `verifying` → `summarizing` → `advancing` → `validating-milestone` → `completing-milestone` → `complete`\n\nSpecial phases: `paused`, `blocked`, `replanning-slice`\n\n## Hierarchy\n\n- **Milestone**: Shippable version (4-10 slices, 1-4 weeks)\n- **Slice**: One demoable vertical capability (1-7 tasks, 1-3 days)\n- **Task**: One context-window-sized unit of work (one session)\n\n<!-- File: src/resources/extensions/gsd/skills/gsd-headless/references/multi-session.md (Tokens: ~1360 | Category: anthropic-skill) -->\n# Multi-Session Orchestration\n\nHow to run and monitor multiple concurrent GSD sessions.\n\n## Architecture\n\nGSD uses **file-based IPC** — no sockets or ports. All coordination happens through JSON files in `.gsd/parallel/`.\n\n```\n.gsd/parallel/\n├── M001.status.json    # Worker heartbeat + state\n├── M001.signal.json    # Coordinator → worker commands (ephemeral)\n├── M002.status.json\n├── M003.status.json\n└── ...\n```\n\n## Worker Isolation\n\nEach worker gets:\n1. **`GSD_MILESTONE_LOCK=M00X`** — state derivation only sees this milestone\n2. **`GSD_PARALLEL_WORKER=1`** — prevents nested parallel spawns\n3. **Own git worktree** at `.gsd/worktrees/M00X/` — branch `milestone/M00X`\n\nWorkers cannot interfere with each other. Each has its own filesystem and git branch.\n\n## Status File Schema\n\nWritten atomically (`.tmp` + rename) by each worker at `.gsd/parallel/<milestoneId>.status.json`:\n\n```json\n{\n  \"milestoneId\": \"M001\",\n  \"pid\": 12345,\n  \"state\": \"running\",\n  \"currentUnit\": {\n    \"type\": \"task\",\n    \"id\": \"T03\",\n    \"startedAt\": 1710000000000\n  },\n  \"completedUnits\": 7,\n  \"cost\": 1.23,\n  \"lastHeartbeat\": 1710000015000,\n  \"startedAt\": 1710000000000,\n  \"worktreePath\": \".gsd/worktrees/M001\"\n}\n```\n\n**States:** `running`, `paused`, `stopped`, `error`\n\n## Signal Files\n\nCoordinator writes to `.gsd/parallel/<milestoneId>.signal.json`. Worker consumes and deletes on next dispatch cycle.\n\n```json\n{\n  \"signal\": \"pause\",\n  \"sentAt\": 1710000020000,\n  \"from\": \"coordinator\"\n}\n```\n\n**Signals:** `pause`, `resume`, `stop`, `rebase`\n\n## Spawning Workers\n\n```bash\n# Spawn worker in its worktree\nGSD_MILESTONE_LOCK=M001 \\\nGSD_PARALLEL_WORKER=1 \\\n  gsd headless --json auto 2>logs/M001.log &\nWORKER_PID=$!\n```\n\nWorkers emit JSONL events on stdout when `--json` is set.\n\n## Monitoring All Workers\n\n```bash\n# Dashboard: enumerate all status files\nfor f in .gsd/parallel/*.status.json; do\n  [ -f \"$f\" ] || continue\n  jq -r '[.milestoneId, .state, (.currentUnit.id // \"idle\"), \"\\(.cost | tostring)$\"] | join(\"\\t\")' \"$f\"\ndone\n\n# Liveness check\nfor f in .gsd/parallel/*.status.json; do\n  PID=$(jq -r '.pid' \"$f\")\n  MID=$(jq -r '.milestoneId' \"$f\")\n  if kill -0 \"$PID\" 2>/dev/null; then\n    echo \"$MID: alive (pid=$PID)\"\n  else\n    echo \"$MID: DEAD (pid=$PID) — cleanup needed\"\n    rm \"$f\"\n  fi\ndone\n```\n\n## Sending Commands\n\n```bash\n# Pause a worker\nsend_signal() {\n  local MID=$1 SIGNAL=$2\n  echo \"{\\\"signal\\\":\\\"$SIGNAL\\\",\\\"sentAt\\\":$(date +%s000),\\\"from\\\":\\\"coordinator\\\"}\" \\\n    > \".gsd/parallel/${MID}.signal.json\"\n}\n\nsend_signal M001 pause\nsend_signal M002 stop\nsend_signal M003 resume\n```\n\n## Budget Enforcement\n\nUse `gsd headless query` for instant aggregate cost:\n```bash\nTOTAL=$(gsd headless query | jq -r '.cost.total')\nCEILING=50.00\nif (( $(echo \"$TOTAL > $CEILING\" | bc -l) )); then\n  echo \"Budget exceeded ($TOTAL > $CEILING) — stopping all\"\n  for f in .gsd/parallel/*.status.json; do\n    MID=$(jq -r '.milestoneId' \"$f\")\n    send_signal \"$MID\" stop\n  done\nfi\n```\n\n## Stale Session Cleanup\n\nA session is stale when:\n- PID is dead (`kill -0 $pid` fails), OR\n- `lastHeartbeat` is older than 30 seconds\n\n```bash\nNOW=$(date +%s000)\nSTALE_THRESHOLD=30000\nfor f in .gsd/parallel/*.status.json; do\n  PID=$(jq -r '.pid' \"$f\")\n  HB=$(jq -r '.lastHeartbeat' \"$f\")\n  AGE=$((NOW - HB))\n  if ! kill -0 \"$PID\" 2>/dev/null || [ \"$AGE\" -gt \"$STALE_THRESHOLD\" ]; then\n    echo \"Stale: $(jq -r '.milestoneId' \"$f\") — removing\"\n    rm \"$f\"\n  fi\ndone\n```\n\n## Multi-Project Orchestration\n\nWithin one project, milestones are tracked automatically in `.gsd/parallel/`. For orchestrating across **multiple projects**, maintain an external registry:\n\n```json\n{\n  \"sessions\": [\n    { \"project\": \"/path/to/project-a\", \"milestoneId\": \"M001\" },\n    { \"project\": \"/path/to/project-b\", \"milestoneId\": \"M001\" },\n    { \"project\": \"/path/to/project-b\", \"milestoneId\": \"M002\" }\n  ]\n}\n```\n\nThen poll each project's `.gsd/parallel/` directory. GSD has no cross-project awareness — the orchestrator must bridge this gap.\n\n## Built-in Parallel Commands\n\nInside an interactive GSD session, these commands manage the parallel orchestrator:\n\n| Command | Description |\n|---------|-------------|\n| `/gsd parallel start` | Analyze eligibility, spawn workers |\n| `/gsd parallel status` | Show all workers, costs, progress |\n| `/gsd parallel stop [MID]` | Stop one or all workers |\n| `/gsd parallel pause [MID]` | Pause without killing |\n| `/gsd parallel resume [MID]` | Resume paused worker |\n| `/gsd parallel merge [MID]` | Merge completed milestone branch |\n\n<!-- File: src/resources/extensions/gsd/skills/gsd-headless/SKILL.md (Tokens: ~2253 | Category: anthropic-skill) -->\n---\nname: gsd-headless\ndescription: Orchestrate GSD (Get Shit Done) projects programmatically via headless CLI. Use when an agent needs to create milestones from specs, execute software development workflows, monitor task progress, check project status, or control GSD execution (pause/stop/skip/steer). Triggers on requests to \"run gsd\", \"create milestone\", \"execute project\", \"check gsd status\", \"orchestrate development\", \"run headless workflow\", or any programmatic interaction with the GSD project management system. Essential for building orchestrators that coordinate multiple GSD workers.\n---\n\n# GSD Headless Orchestration\n\nRun GSD commands without TUI via `gsd headless`. Spawns an RPC child process, auto-responds to UI prompts, streams progress.\n\n## Command Syntax\n\n```bash\ngsd headless [flags] [command] [args...]\n```\n\n**Flags:**\n- `--timeout N` — overall timeout in ms (default 300000)\n- `--json` — JSONL event stream to stdout\n- `--model ID` — override LLM model\n- `--verbose` — show tool calls in progress output\n- `--supervised` — forward interactive UI requests to orchestrator via stdout/stdin\n- `--response-timeout N` — timeout for orchestrator response in supervised mode (default 30000)\n- `--max-restarts N` — auto-restart on crash with backoff (default 3, 0 to disable)\n- `--answers <path>` — pre-supply answers and secrets from JSON file\n- `--events <types>` — filter JSONL output to specific event types (comma-separated, implies `--json`)\n\n**Exit codes:** 0=complete, 1=error/timeout, 2=blocked\n\n## Core Workflows\n\n### 1. Create + Execute a Milestone (end-to-end)\n\n```bash\ngsd headless new-milestone --context spec.md --auto\n```\n\nReads spec, bootstraps `.gsd/`, creates milestone, then chains into auto-mode executing all phases (discuss → research → plan → execute → summarize → complete).\n\nExtra flags for `new-milestone`: `--context <path>` (use `-` for stdin), `--context-text <text>`, `--auto`.\n\n### 2. Run All Queued Work\n\n```bash\ngsd headless auto\n```\n\nDefault command. Loops through all pending units until milestone complete or blocked.\n\n### 3. Run One Unit\n\n```bash\ngsd headless next\n```\n\nExecute exactly one unit (task/slice/milestone step), then exit. Ideal for step-by-step orchestration with external decision logic between steps.\n\n### 4. Instant State Snapshot (no LLM)\n\n```bash\ngsd headless query\n```\n\nReturns a single JSON object with the full project snapshot — no LLM session, instant (~50ms). **This is the recommended way for orchestrators to inspect state.**\n\n```json\n{\n  \"state\": { \"phase\": \"executing\", \"activeMilestone\": {...}, \"activeSlice\": {...}, \"progress\": {...}, \"registry\": [...] },\n  \"next\":  { \"action\": \"dispatch\", \"unitType\": \"execute-task\", \"unitId\": \"M001/S01/T01\" },\n  \"cost\":  { \"workers\": [{ \"milestoneId\": \"M001\", \"cost\": 1.50, ... }], \"total\": 1.50 }\n}\n```\n\n```bash\n# What phase is the project in?\ngsd headless query | jq '.state.phase'\n\n# What would auto-mode do next?\ngsd headless query | jq '.next'\n\n# Total spend across parallel workers\ngsd headless query | jq '.cost.total'\n```\n\n### 5. Dispatch Specific Phase\n\n```bash\ngsd headless dispatch research|plan|execute|complete|reassess|uat|replan\n```\n\nForce-route to a specific phase, bypassing normal state-machine routing.\n\n## Orchestrator Patterns\n\n### Poll-and-React Loop\n\n```bash\n# Instant state check — no LLM cost\nPHASE=$(gsd headless query | jq -r '.state.phase')\nNEXT_ACTION=$(gsd headless query | jq -r '.next.action')\n\ncase \"$PHASE\" in\n  complete) echo \"Done\" ;;\n  blocked)  echo \"Needs intervention\" ;;\n  *)        [ \"$NEXT_ACTION\" = \"dispatch\" ] && gsd headless next ;;\nesac\n```\n\n### Step-by-Step with Monitoring\n\n```bash\nwhile true; do\n  gsd headless next\n  EXIT=$?\n  [ $EXIT -ne 0 ] && break\n  # Instant progress check between steps\n  gsd headless query | jq '{phase: .state.phase, progress: .state.progress}'\ndone\n```\n\n### Multi-Session Orchestration\n\nGSD tracks concurrent workers via file-based IPC in `.gsd/parallel/`. See [references/multi-session.md](references/multi-session.md) for the full architecture.\n\n**Quick overview:**\n\nEach worker spawns with `GSD_MILESTONE_LOCK=M00X` + its own git worktree. Workers write heartbeats to `.gsd/parallel/<milestoneId>.status.json`. The orchestrator enumerates all status files to get a dashboard of all workers, and sends commands via signal files.\n\n```bash\n# Spawn a worker for milestone M001 in its worktree\nGSD_MILESTONE_LOCK=M001 GSD_PARALLEL_WORKER=1 \\\n  gsd headless --json auto \\\n  --cwd .gsd/worktrees/M001 2>worker-M001.log &\n\n# Monitor all workers: read .gsd/parallel/*.status.json\nfor f in .gsd/parallel/*.status.json; do\n  jq '{mid: .milestoneId, state: .state, unit: .currentUnit.id, cost: .cost}' \"$f\"\ndone\n\n# Send pause signal to M001\necho '{\"signal\":\"pause\",\"sentAt\":'$(date +%s000)',\"from\":\"coordinator\"}' \\\n  > .gsd/parallel/M001.signal.json\n```\n\n**Status file fields:** `milestoneId`, `pid`, `state` (running/paused/stopped/error), `currentUnit`, `completedUnits`, `cost`, `lastHeartbeat`, `startedAt`, `worktreePath`.\n\n**Signal commands:** `pause`, `resume`, `stop`, `rebase`.\n\n**Liveness detection:** PID alive check (`kill -0 $pid`) + heartbeat freshness (30s timeout). Stale sessions are auto-cleaned.\n\n**For multiple projects:** each project has its own `.gsd/` directory. The orchestrator must track `(projectPath, milestoneId)` tuples externally.\n\n### JSONL Event Stream\n\nUse `--json` to get real-time events on stdout for downstream processing:\n\n```bash\ngsd headless --json auto 2>/dev/null | while read -r line; do\n  TYPE=$(echo \"$line\" | jq -r '.type')\n  case \"$TYPE\" in\n    tool_execution_start) echo \"Tool: $(echo \"$line\" | jq -r '.toolName')\" ;;\n    extension_ui_request) echo \"GSD: $(echo \"$line\" | jq -r '.message // .title // empty')\" ;;\n    agent_end) echo \"Session ended\" ;;\n  esac\ndone\n```\n\nEvent types: `agent_start`, `agent_end`, `tool_execution_start`, `tool_execution_end`, `extension_ui_request`, `message_update`, `error`.\n\n### Filtered Event Stream\n\nUse `--events` to receive only specific event types — reduces noise for orchestrators:\n\n```bash\n# Only phase-relevant events\ngsd headless --events agent_end,extension_ui_request auto 2>/dev/null\n\n# Only tool execution events\ngsd headless --events tool_execution_start,tool_execution_end auto\n```\n\nThe filter applies only to stdout output. Internal processing (completion detection, supervised mode, answer injection) is unaffected — all events are still processed internally.\n\nAvailable event types: `agent_start`, `agent_end`, `tool_execution_start`, `tool_execution_end`, `tool_execution_update`, `extension_ui_request`, `message_start`, `message_end`, `message_update`, `turn_start`, `turn_end`.\n\n## Answer Injection\n\nPre-supply answers and secrets for headless runs via `--answers`:\n\n```bash\ngsd headless --answers answers.json auto\n```\n\nAnswer file schema:\n```json\n{\n  \"questions\": { \"question_id\": \"selected_option\" },\n  \"secrets\": { \"API_KEY\": \"sk-...\" },\n  \"defaults\": { \"strategy\": \"first_option\" }\n}\n```\n\n- **questions** — question ID → answer (string or string[])\n- **secrets** — env var → value, injected into child process env\n- **defaults.strategy** — `\"first_option\"` (default) or `\"cancel\"` for unmatched\n\nSee [references/answer-injection.md](references/answer-injection.md) for full details.\n\n## GSD Project Structure\n\nAll state lives in `.gsd/` as markdown files (version-controllable):\n\n```\n.gsd/\n  milestones/M001/\n    M001-CONTEXT.md      # Requirements, scope, decisions\n    M001-ROADMAP.md      # Slices with tasks, dependencies, checkboxes\n    M001-SUMMARY.md      # Completion summary\n    slices/S01/\n      S01-PLAN.md        # Task list\n      S01-SUMMARY.md     # Slice summary with frontmatter\n      tasks/T01-PLAN.md  # Individual task spec\n```\n\nState is derived from files on disk — checkboxes in ROADMAP.md are the source of truth for completion.\n\n## All Headless Commands\n\nQuick reference — see [references/commands.md](references/commands.md) for the complete list.\n\n| Command | Purpose |\n|---------|---------|\n| `auto` | Run all queued units (default) |\n| `next` | Run one unit |\n| `query` | Instant JSON snapshot — state, next dispatch, costs (no LLM) |\n| `new-milestone` | Create milestone from spec |\n| `queue` | Queue/reorder milestones |\n| `history` | View execution history |\n| `stop` / `pause` | Control auto-mode |\n| `dispatch <phase>` | Force specific phase |\n| `skip` / `undo` | Unit control |\n| `doctor` | Health check + auto-fix |\n| `steer <desc>` | Hard-steer plan mid-execution |\n\n<!-- File: src/resources/extensions/gsd/templates/milestone-summary.md (Tokens: ~601 | Category: anthropic-skill) -->\n---\nid: {{milestoneId}}\nprovides:\n  - {{whatThisMilestoneProvides}}\nkey_decisions:\n  - {{decision}}\npatterns_established:\n  - {{pattern}}\nobservability_surfaces:\n  - {{status endpoint, structured log, persisted failure state, diagnostic command, or none}}\nrequirement_outcomes:\n  - id: {{requirementId}}\n    from_status: {{active|blocked|deferred}}\n    to_status: {{validated|deferred|blocked|out_of_scope}}\n    proof: {{whatEvidenceSupportsThisTransition}}\nduration: {{duration}}\nverification_result: passed\ncompleted_at: {{date}}\n---\n\n# {{milestoneId}}: {{milestoneTitle}}\n\n<!-- One-liner must say what the milestone actually delivered, not just that it completed.\n     Good: \"State machine integrity with completing-milestone gating, doctor audits, and observability validation\"\n     Bad: \"Milestone 2 completed\" -->\n\n**{{oneLiner}}**\n\n## What Happened\n\n<!-- Cross-slice narrative: compress all slice summaries into a coherent story.\n     Focus on what was built, how the slices connected, and what the milestone\n     achieved as a whole — not a task-by-task replay. -->\n\n{{crossSliceNarrative}}\n\n## Cross-Slice Verification\n\n<!-- How were the milestone's success criteria verified?\n     Reference specific tests, commands, browser checks, or observable behaviors.\n     Each success criterion from the roadmap should have a corresponding verification entry. -->\n\n{{howSuccessCriteriaWereVerified}}\n\n## Requirement Changes\n\n<!-- Transitions with evidence. Each requirement that changed status during this milestone\n     should be listed with the proof that supports the transition. -->\n\n- {{requirementId}}: {{fromStatus}} → {{toStatus}} — {{evidence}}\n\n## Decision Re-evaluation\n\n<!-- Review decisions from this milestone. OMIT if no decisions need re-evaluation. -->\n\n| Decision | Original Rationale | Still Valid? | Action |\n|----------|-------------------|-------------|--------|\n| {{decisionId}} | {{originalRationale}} | {{yes/no/partially}} | {{keep/revise/supersede}} |\n\n## Forward Intelligence\n\n<!-- Write what you wish you'd known at the start of this milestone.\n     This section is read by the next milestone's planning and research steps.\n     Be specific and concrete — this is the most valuable context you can transfer. -->\n\n### What the next milestone should know\n- {{insightThatWouldHelpDownstreamWork}}\n\n### What's fragile\n- {{fragileAreaOrThinImplementation}} — {{whyItMatters}}\n\n### Authoritative diagnostics\n- {{whereAFutureAgentShouldLookFirst}} — {{whyThisSignalIsTrustworthy}}\n\n### What assumptions changed\n- {{originalAssumption}} — {{whatActuallyHappened}}\n\n## Files Created/Modified\n\n- `{{filePath}}` — {{description}}\n- `{{filePath}}` — {{description}}\n\n<!-- File: src/resources/extensions/gsd/templates/slice-summary.md (Tokens: ~748 | Category: anthropic-skill) -->\n---\nid: {{sliceId}}\nparent: {{milestoneId}}\nmilestone: {{milestoneId}}\nprovides:\n  - {{whatThisSliceProvides}}\nrequires:\n  - slice: {{depSliceId}}\n    provides: {{whatWasConsumed}}\naffects:\n  - {{downstreamSliceId}}\nkey_files:\n  - {{filePath}}\nkey_decisions:\n  - {{decision}}\npatterns_established:\n  - {{pattern}}\nobservability_surfaces:\n  - {{status endpoint, structured log, persisted failure state, diagnostic command, or none}}\ndrill_down_paths:\n  - {{pathToTaskSummary}}\nduration: {{duration}}\nverification_result: passed\ncompleted_at: {{date}}\n---\n\n# {{sliceId}}: {{sliceTitle}}\n\n<!-- One-liner must say what actually shipped, not just that work completed.\n     Good: \"Structured job status endpoint with persisted failure diagnostics\"\n     Bad: \"Status feature implemented\" -->\n\n**{{oneLiner}}**\n\n## What Happened\n\n{{narrative — compress task summaries into a coherent story}}\n\n## Verification\n\n{{whatWasVerifiedAcrossAllTasks — tests, builds, manual checks}}\n\n<!-- If the project has no REQUIREMENTS.md, omit all four requirement sections below entirely — do not fill them with \"none\". These sections only apply when requirements are being actively tracked. -->\n## Requirements Advanced\n\n- {{requirementId}} — {{howThisSliceAdvancedIt}}\n\n## Requirements Validated\n\n- {{requirementId}} — {{whatProofNowMakesItValidated}}\n\n## New Requirements Surfaced\n\n- {{newRequirementOr_none}}\n\n## Requirements Invalidated or Re-scoped\n\n- {{requirementIdOr_none}} — {{what changed}}\n\n## Operational Readiness\n\n<!-- Q8: How will ops know it's healthy/broken? OMIT ENTIRELY for simple slices with no runtime concerns. -->\n\n- **Health signal**: {{howToConfirmHealthy — health endpoint, heartbeat log, metric, or N/A}}\n- **Failure signal**: {{howToDetectBroken — error rate spike, alert, log pattern, or N/A}}\n- **Recovery**: {{selfRecoverOrRestart — auto-reconnect, circuit breaker, manual restart, or N/A}}\n- **Monitoring gaps**: {{silentFailureModes — background jobs, cache eviction, memory pressure, or none}}\n\n## Deviations\n\n<!-- Deviations are unplanned changes to the written plan, not ordinary debugging inside the plan's intended scope. -->\n\n{{deviationsFromPlan_OR_none}}\n\n## Known Limitations\n\n<!-- Known limitations are real gaps, rough edges, or deferred constraints that still exist after this slice shipped. -->\n\n{{whatDoesntWorkYet_OR_whatWasDeferredToLaterSlices}}\n\n## Follow-ups\n\n<!-- Follow-ups are concrete next actions discovered during execution, not a restatement of known limitations. -->\n\n{{workDeferredOrDiscoveredDuringExecution_OR_none}}\n\n## Files Created/Modified\n\n- `{{filePath}}` — {{description}}\n- `{{filePath}}` — {{description}}\n\n## Forward Intelligence\n\n<!-- Write what you wish you'd known at the start of this slice.\n     This section is read by the next slice's planning and research steps.\n     Be specific and concrete — this is the most valuable context you can transfer. -->\n\n### What the next slice should know\n- {{insightThatWouldHelpDownstreamWork}}\n\n### What's fragile\n- {{fragileAreaOrThinImplementation}} — {{whyItMatters}}\n\n### Authoritative diagnostics\n- {{whereAFutureAgentShouldLookFirst}} — {{whyThisSignalIsTrustworthy}}\n\n### What assumptions changed\n- {{originalAssumption}} — {{whatActuallyHappened}}\n\n<!-- File: src/resources/extensions/gsd/templates/task-summary.md (Tokens: ~422 | Category: anthropic-skill) -->\n---\nid: {{taskId}}\nparent: {{sliceId}}\nmilestone: {{milestoneId}}\nprovides:\n  - {{whatThisTaskProvides}}\nkey_files:\n  - {{filePath}}\nkey_decisions:\n  - {{decision}}\npatterns_established:\n  - {{pattern}}\nobservability_surfaces:\n  - {{status endpoint, structured log, persisted failure state, diagnostic command, or none}}\nduration: {{duration}}\nverification_result: passed\ncompleted_at: {{date}}\n# Set blocker_discovered: true only if execution revealed the remaining slice plan\n# is fundamentally invalid (wrong API, missing capability, architectural mismatch).\n# Do NOT set true for ordinary bugs, minor deviations, or fixable issues.\nblocker_discovered: false\n---\n\n# {{taskId}}: {{taskTitle}}\n\n<!-- One-liner must say what actually shipped, not just that work completed.\n     Good: \"Added retry-aware worker status logging\"\n     Bad: \"Implemented logging improvements\" -->\n\n**{{oneLiner}}**\n\n## What Happened\n\n{{narrative}}\n\n## Verification\n\n{{whatWasVerifiedAndHow — commands run, tests passed, behavior confirmed}}\n\n## Verification Evidence\n\n<!-- Populated from verification gate output. If the gate ran, fill in the table below.\n     If no gate ran (e.g., no verification commands discovered), note that. -->\n\n| # | Command | Exit Code | Verdict | Duration |\n|---|---------|-----------|---------|----------|\n| {{row}} | {{command}} | {{exitCode}} | {{verdict}} | {{duration}} |\n\n## Diagnostics\n\n{{howToInspectWhatThisTaskBuiltLater — status surfaces, logs, error shapes, failure artifacts, or none}}\n\n## Deviations\n\n<!-- Deviations are unplanned changes to the written task plan, not ordinary debugging during implementation. -->\n\n{{deviationsFromPlan_OR_none}}\n\n## Known Issues\n\n{{issuesDiscoveredButNotFixed_OR_none}}\n\n## Files Created/Modified\n\n- `{{filePath}}` — {{description}}\n- `{{filePath}}` — {{description}}\n\n<!-- File: src/resources/skills/accessibility/references/WCAG.md (Tokens: ~1980 | Category: anthropic-skill) -->\n# WCAG 2.1 Quick Reference\n\n## Success criteria by level\n\n### Level A (minimum)\n\n| Criterion | Description |\n|-----------|-------------|\n| **1.1.1** Non-text Content | All images, icons have text alternatives |\n| **1.2.1** Audio-only/Video-only | Provide transcript or audio description |\n| **1.2.2** Captions | Video with audio has captions |\n| **1.2.3** Audio Description | Video has audio description |\n| **1.3.1** Info and Relationships | Information conveyed through presentation is available programmatically |\n| **1.3.2** Meaningful Sequence | Reading order is logical |\n| **1.3.3** Sensory Characteristics | Instructions don't rely solely on shape, color, size, location, orientation, or sound |\n| **1.4.1** Use of Color | Color is not the only visual means of conveying information |\n| **1.4.2** Audio Control | Audio playing automatically can be paused/stopped |\n| **2.1.1** Keyboard | All functionality available via keyboard |\n| **2.1.2** No Keyboard Trap | Keyboard focus can be moved away from any component |\n| **2.1.4** Character Key Shortcuts | Single-key shortcuts can be turned off or remapped |\n| **2.2.1** Timing Adjustable | Time limits can be extended |\n| **2.2.2** Pause, Stop, Hide | Moving/blinking content can be paused |\n| **2.3.1** Three Flashes | Nothing flashes more than 3 times per second |\n| **2.4.1** Bypass Blocks | Skip link or landmark navigation available |\n| **2.4.2** Page Titled | Pages have descriptive titles |\n| **2.4.3** Focus Order | Focus order preserves meaning |\n| **2.4.4** Link Purpose | Link purpose clear from link text or context |\n| **2.5.1** Pointer Gestures | Multi-point gestures have single-pointer alternatives |\n| **2.5.2** Pointer Cancellation | Down-event doesn't trigger action (use up-event or click) |\n| **2.5.3** Label in Name | Accessible name contains visible label text |\n| **2.5.4** Motion Actuation | Motion-triggered functions have alternatives |\n| **3.1.1** Language of Page | Default language specified in HTML |\n| **3.2.1** On Focus | Focus doesn't trigger unexpected changes |\n| **3.2.2** On Input | Input doesn't trigger unexpected changes |\n| **3.3.1** Error Identification | Input errors clearly described |\n| **3.3.2** Labels or Instructions | Form inputs have labels or instructions |\n| **4.1.1** Parsing | HTML is well-formed (no duplicate IDs, proper nesting) |\n| **4.1.2** Name, Role, Value | UI components have accessible names and correct roles |\n\n### Level AA (standard)\n\n| Criterion | Description |\n|-----------|-------------|\n| **1.2.4** Captions (Live) | Live audio has captions |\n| **1.2.5** Audio Description | Pre-recorded video has audio description |\n| **1.3.4** Orientation | Content doesn't restrict orientation |\n| **1.3.5** Identify Input Purpose | Input purpose can be programmatically determined |\n| **1.4.3** Contrast (Minimum) | 4.5:1 for normal text, 3:1 for large text |\n| **1.4.4** Resize Text | Text can be resized to 200% without loss of functionality |\n| **1.4.5** Images of Text | Text used instead of images of text |\n| **1.4.10** Reflow | Content reflows at 320px width without horizontal scroll |\n| **1.4.11** Non-text Contrast | UI components have 3:1 contrast |\n| **1.4.12** Text Spacing | Content adapts to text spacing changes |\n| **1.4.13** Content on Hover/Focus | Additional content is dismissible, hoverable, persistent |\n| **2.4.5** Multiple Ways | Multiple ways to find pages |\n| **2.4.6** Headings and Labels | Headings and labels are descriptive |\n| **2.4.7** Focus Visible | Focus indicator is visible |\n| **3.1.2** Language of Parts | Language changes are marked |\n| **3.2.3** Consistent Navigation | Navigation is consistent across pages |\n| **3.2.4** Consistent Identification | Same functionality uses same labels |\n| **3.3.3** Error Suggestion | Error corrections suggested when known |\n| **3.3.4** Error Prevention (Legal) | Actions can be reversed or confirmed |\n| **4.1.3** Status Messages | Status messages announced to screen readers |\n\n### Level AAA (enhanced)\n\n| Criterion | Description |\n|-----------|-------------|\n| **1.4.6** Contrast (Enhanced) | 7:1 for normal text, 4.5:1 for large text |\n| **1.4.8** Visual Presentation | Foreground/background colors can be selected |\n| **1.4.9** Images of Text (No Exception) | No images of text |\n| **2.1.3** Keyboard (No Exception) | All functionality keyboard accessible |\n| **2.2.3** No Timing | No time limits |\n| **2.2.4** Interruptions | Interruptions can be postponed |\n| **2.2.5** Re-authenticating | Data preserved on re-authentication |\n| **2.2.6** Timeouts | Users warned about data loss from inactivity |\n| **2.3.2** Three Flashes | No content flashes more than 3 times |\n| **2.3.3** Animation from Interactions | Motion animation can be disabled |\n| **2.4.8** Location | User location within site is available |\n| **2.4.9** Link Purpose (Link Only) | Link purpose clear from link text alone |\n| **2.4.10** Section Headings | Sections have headings |\n| **3.1.3** Unusual Words | Definitions available for unusual words |\n| **3.1.4** Abbreviations | Abbreviations expanded |\n| **3.1.5** Reading Level | Alternative content for complex text |\n| **3.1.6** Pronunciation | Pronunciation available where needed |\n| **3.2.5** Change on Request | Changes initiated only by user |\n| **3.3.5** Help | Context-sensitive help available |\n| **3.3.6** Error Prevention (All) | All form submissions can be reviewed |\n\n## Common ARIA patterns\n\n### Buttons\n```html\n<button>Label</button>\n<!-- or -->\n<button aria-label=\"Close dialog\">×</button>\n```\n\n### Links\n```html\n<a href=\"/page\">Descriptive link text</a>\n<!-- External links -->\n<a href=\"https://external.com\" target=\"_blank\" rel=\"noopener\">\n  External site\n  <span class=\"visually-hidden\">(opens in new tab)</span>\n</a>\n```\n\n### Form fields\n```html\n<label for=\"email\">Email address</label>\n<input type=\"email\" id=\"email\" aria-describedby=\"email-hint\">\n<p id=\"email-hint\">We'll never share your email.</p>\n```\n\n### Error states\n```html\n<label for=\"email\">Email</label>\n<input type=\"email\" id=\"email\" aria-invalid=\"true\" aria-describedby=\"email-error\">\n<p id=\"email-error\" role=\"alert\">Please enter a valid email address.</p>\n```\n\n### Navigation\n```html\n<nav aria-label=\"Main\">\n  <ul>\n    <li><a href=\"/\" aria-current=\"page\">Home</a></li>\n    <li><a href=\"/about\">About</a></li>\n  </ul>\n</nav>\n```\n\n### Modals\n```html\n<div role=\"dialog\" aria-modal=\"true\" aria-labelledby=\"dialog-title\">\n  <h2 id=\"dialog-title\">Confirm Action</h2>\n  <!-- content -->\n</div>\n```\n\n### Live regions\n```html\n<!-- Polite (waits for pause in speech) -->\n<div aria-live=\"polite\">Status update here</div>\n\n<!-- Assertive (interrupts immediately) -->\n<div aria-live=\"assertive\" role=\"alert\">Error message here</div>\n\n<!-- Status (polite, implicit) -->\n<div role=\"status\">Loading complete</div>\n```\n\n## Testing tools\n\n| Tool | Type | URL |\n|------|------|-----|\n| axe DevTools | Browser extension | [deque.com/axe](https://www.deque.com/axe/) |\n| WAVE | Browser extension | [wave.webaim.org](https://wave.webaim.org/) |\n| Lighthouse | Built into Chrome | DevTools → Lighthouse |\n| NVDA | Screen reader (Windows) | [nvaccess.org](https://www.nvaccess.org/) |\n| VoiceOver | Screen reader (Mac) | Built into macOS |\n| Colour Contrast Analyser | Desktop app | [tpgi.com](https://www.tpgi.com/color-contrast-checker/) |\n\n<!-- File: src/resources/skills/accessibility/SKILL.md (Tokens: ~3275 | Category: anthropic-skill) -->\n---\nname: accessibility\ndescription: Audit and improve web accessibility following WCAG 2.1 guidelines. Use when asked to \"improve accessibility\", \"a11y audit\", \"WCAG compliance\", \"screen reader support\", \"keyboard navigation\", or \"make accessible\".\nlicense: MIT\nmetadata:\n  author: web-quality-skills\n  version: \"1.0\"\n---\n\n# Accessibility (a11y)\n\nComprehensive accessibility guidelines based on WCAG 2.1 and Lighthouse accessibility audits. Goal: make content usable by everyone, including people with disabilities.\n\n## WCAG Principles: POUR\n\n| Principle | Description |\n|-----------|-------------|\n| **P**erceivable | Content can be perceived through different senses |\n| **O**perable | Interface can be operated by all users |\n| **U**nderstandable | Content and interface are understandable |\n| **R**obust | Content works with assistive technologies |\n\n## Conformance levels\n\n| Level | Requirement | Target |\n|-------|-------------|--------|\n| **A** | Minimum accessibility | Must pass |\n| **AA** | Standard compliance | Should pass (legal requirement in many jurisdictions) |\n| **AAA** | Enhanced accessibility | Nice to have |\n\n---\n\n## Perceivable\n\n### Text alternatives (1.1)\n\n**Images require alt text:**\n```html\n<!-- ❌ Missing alt -->\n<img src=\"chart.png\">\n\n<!-- ✅ Descriptive alt -->\n<img src=\"chart.png\" alt=\"Bar chart showing 40% increase in Q3 sales\">\n\n<!-- ✅ Decorative image (empty alt) -->\n<img src=\"decorative-border.png\" alt=\"\" role=\"presentation\">\n\n<!-- ✅ Complex image with longer description -->\n<figure>\n  <img src=\"infographic.png\" alt=\"2024 market trends infographic\" \n       aria-describedby=\"infographic-desc\">\n  <figcaption id=\"infographic-desc\">\n    <!-- Detailed description -->\n  </figcaption>\n</figure>\n```\n\n**Icon buttons need accessible names:**\n```html\n<!-- ❌ No accessible name -->\n<button><svg><!-- menu icon --></svg></button>\n\n<!-- ✅ Using aria-label -->\n<button aria-label=\"Open menu\">\n  <svg aria-hidden=\"true\"><!-- menu icon --></svg>\n</button>\n\n<!-- ✅ Using visually hidden text -->\n<button>\n  <svg aria-hidden=\"true\"><!-- menu icon --></svg>\n  <span class=\"visually-hidden\">Open menu</span>\n</button>\n```\n\n**Visually hidden class:**\n```css\n.visually-hidden {\n  position: absolute;\n  width: 1px;\n  height: 1px;\n  padding: 0;\n  margin: -1px;\n  overflow: hidden;\n  clip: rect(0, 0, 0, 0);\n  white-space: nowrap;\n  border: 0;\n}\n```\n\n### Color contrast (1.4.3, 1.4.6)\n\n| Text Size | AA minimum | AAA enhanced |\n|-----------|------------|--------------|\n| Normal text (< 18px / < 14px bold) | 4.5:1 | 7:1 |\n| Large text (≥ 18px / ≥ 14px bold) | 3:1 | 4.5:1 |\n| UI components & graphics | 3:1 | 3:1 |\n\n```css\n/* ❌ Low contrast (2.5:1) */\n.low-contrast {\n  color: #999;\n  background: #fff;\n}\n\n/* ✅ Sufficient contrast (7:1) */\n.high-contrast {\n  color: #333;\n  background: #fff;\n}\n\n/* ✅ Focus states need contrast too */\n:focus-visible {\n  outline: 2px solid #005fcc;\n  outline-offset: 2px;\n}\n```\n\n**Don't rely on color alone:**\n```html\n<!-- ❌ Only color indicates error -->\n<input class=\"error-border\">\n<style>.error-border { border-color: red; }</style>\n\n<!-- ✅ Color + icon + text -->\n<div class=\"field-error\">\n  <input aria-invalid=\"true\" aria-describedby=\"email-error\">\n  <span id=\"email-error\" class=\"error-message\">\n    <svg aria-hidden=\"true\"><!-- error icon --></svg>\n    Please enter a valid email address\n  </span>\n</div>\n```\n\n### Media alternatives (1.2)\n\n```html\n<!-- Video with captions -->\n<video controls>\n  <source src=\"video.mp4\" type=\"video/mp4\">\n  <track kind=\"captions\" src=\"captions.vtt\" srclang=\"en\" label=\"English\" default>\n  <track kind=\"descriptions\" src=\"descriptions.vtt\" srclang=\"en\" label=\"Descriptions\">\n</video>\n\n<!-- Audio with transcript -->\n<audio controls>\n  <source src=\"podcast.mp3\" type=\"audio/mp3\">\n</audio>\n<details>\n  <summary>Transcript</summary>\n  <p>Full transcript text...</p>\n</details>\n```\n\n---\n\n## Operable\n\n### Keyboard accessible (2.1)\n\n**All functionality must be keyboard accessible:**\n```javascript\n// ❌ Only handles click\nelement.addEventListener('click', handleAction);\n\n// ✅ Handles both click and keyboard\nelement.addEventListener('click', handleAction);\nelement.addEventListener('keydown', (e) => {\n  if (e.key === 'Enter' || e.key === ' ') {\n    e.preventDefault();\n    handleAction();\n  }\n});\n```\n\n**No keyboard traps:**\n```javascript\n// Modal focus management\nfunction openModal(modal) {\n  const focusableElements = modal.querySelectorAll(\n    'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n  );\n  const firstElement = focusableElements[0];\n  const lastElement = focusableElements[focusableElements.length - 1];\n  \n  // Trap focus within modal\n  modal.addEventListener('keydown', (e) => {\n    if (e.key === 'Tab') {\n      if (e.shiftKey && document.activeElement === firstElement) {\n        e.preventDefault();\n        lastElement.focus();\n      } else if (!e.shiftKey && document.activeElement === lastElement) {\n        e.preventDefault();\n        firstElement.focus();\n      }\n    }\n    if (e.key === 'Escape') {\n      closeModal();\n    }\n  });\n  \n  firstElement.focus();\n}\n```\n\n### Focus visible (2.4.7)\n\n```css\n/* ❌ Never remove focus outlines */\n*:focus { outline: none; }\n\n/* ✅ Use :focus-visible for keyboard-only focus */\n:focus {\n  outline: none;\n}\n\n:focus-visible {\n  outline: 2px solid #005fcc;\n  outline-offset: 2px;\n}\n\n/* ✅ Or custom focus styles */\nbutton:focus-visible {\n  box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.5);\n}\n```\n\n### Skip links (2.4.1)\n\n```html\n<body>\n  <a href=\"#main-content\" class=\"skip-link\">Skip to main content</a>\n  <header><!-- navigation --></header>\n  <main id=\"main-content\" tabindex=\"-1\">\n    <!-- main content -->\n  </main>\n</body>\n```\n\n```css\n.skip-link {\n  position: absolute;\n  top: -40px;\n  left: 0;\n  background: #000;\n  color: #fff;\n  padding: 8px 16px;\n  z-index: 100;\n}\n\n.skip-link:focus {\n  top: 0;\n}\n```\n\n### Timing (2.2)\n\n```javascript\n// Allow users to extend time limits\nfunction showSessionWarning() {\n  const modal = createModal({\n    title: 'Session Expiring',\n    content: 'Your session will expire in 2 minutes.',\n    actions: [\n      { label: 'Extend session', action: extendSession },\n      { label: 'Log out', action: logout }\n    ],\n    timeout: 120000 // 2 minutes to respond\n  });\n}\n```\n\n### Motion (2.3)\n\n```css\n/* Respect reduced motion preference */\n@media (prefers-reduced-motion: reduce) {\n  *,\n  *::before,\n  *::after {\n    animation-duration: 0.01ms !important;\n    animation-iteration-count: 1 !important;\n    transition-duration: 0.01ms !important;\n    scroll-behavior: auto !important;\n  }\n}\n```\n\n---\n\n## Understandable\n\n### Page language (3.1.1)\n\n```html\n<!-- ❌ No language specified -->\n<html>\n\n<!-- ✅ Language specified -->\n<html lang=\"en\">\n\n<!-- ✅ Language changes within page -->\n<p>The French word for hello is <span lang=\"fr\">bonjour</span>.</p>\n```\n\n### Consistent navigation (3.2.3)\n\n```html\n<!-- Navigation should be consistent across pages -->\n<nav aria-label=\"Main\">\n  <ul>\n    <li><a href=\"/\" aria-current=\"page\">Home</a></li>\n    <li><a href=\"/products\">Products</a></li>\n    <li><a href=\"/about\">About</a></li>\n  </ul>\n</nav>\n```\n\n### Form labels (3.3.2)\n\n```html\n<!-- ❌ No label association -->\n<input type=\"email\" placeholder=\"Email\">\n\n<!-- ✅ Explicit label -->\n<label for=\"email\">Email address</label>\n<input type=\"email\" id=\"email\" name=\"email\" \n       autocomplete=\"email\" required>\n\n<!-- ✅ Implicit label -->\n<label>\n  Email address\n  <input type=\"email\" name=\"email\" autocomplete=\"email\" required>\n</label>\n\n<!-- ✅ With instructions -->\n<label for=\"password\">Password</label>\n<input type=\"password\" id=\"password\" \n       aria-describedby=\"password-requirements\">\n<p id=\"password-requirements\">\n  Must be at least 8 characters with one number.\n</p>\n```\n\n### Error handling (3.3.1, 3.3.3)\n\n```html\n<!-- Announce errors to screen readers -->\n<form novalidate>\n  <div class=\"field\" aria-live=\"polite\">\n    <label for=\"email\">Email</label>\n    <input type=\"email\" id=\"email\" \n           aria-invalid=\"true\"\n           aria-describedby=\"email-error\">\n    <p id=\"email-error\" class=\"error\" role=\"alert\">\n      Please enter a valid email address (e.g., name@example.com)\n    </p>\n  </div>\n</form>\n```\n\n```javascript\n// Focus first error on submit\nform.addEventListener('submit', (e) => {\n  const firstError = form.querySelector('[aria-invalid=\"true\"]');\n  if (firstError) {\n    e.preventDefault();\n    firstError.focus();\n    \n    // Announce error summary\n    const errorSummary = document.getElementById('error-summary');\n    errorSummary.textContent = `${errors.length} errors found. Please fix them and try again.`;\n    errorSummary.focus();\n  }\n});\n```\n\n---\n\n## Robust\n\n### Valid HTML (4.1.1)\n\n```html\n<!-- ❌ Duplicate IDs -->\n<div id=\"content\">...</div>\n<div id=\"content\">...</div>\n\n<!-- ❌ Invalid nesting -->\n<a href=\"/\"><button>Click</button></a>\n\n<!-- ✅ Unique IDs -->\n<div id=\"main-content\">...</div>\n<div id=\"sidebar-content\">...</div>\n\n<!-- ✅ Proper nesting -->\n<a href=\"/\" class=\"button-link\">Click</a>\n```\n\n### ARIA usage (4.1.2)\n\n**Prefer native elements:**\n```html\n<!-- ❌ ARIA role on div -->\n<div role=\"button\" tabindex=\"0\">Click me</div>\n\n<!-- ✅ Native button -->\n<button>Click me</button>\n\n<!-- ❌ ARIA checkbox -->\n<div role=\"checkbox\" aria-checked=\"false\">Option</div>\n\n<!-- ✅ Native checkbox -->\n<label><input type=\"checkbox\"> Option</label>\n```\n\n**When ARIA is needed:**\n```html\n<!-- Custom tabs component -->\n<div role=\"tablist\" aria-label=\"Product information\">\n  <button role=\"tab\" id=\"tab-1\" aria-selected=\"true\" \n          aria-controls=\"panel-1\">Description</button>\n  <button role=\"tab\" id=\"tab-2\" aria-selected=\"false\" \n          aria-controls=\"panel-2\" tabindex=\"-1\">Reviews</button>\n</div>\n<div role=\"tabpanel\" id=\"panel-1\" aria-labelledby=\"tab-1\">\n  <!-- Panel content -->\n</div>\n<div role=\"tabpanel\" id=\"panel-2\" aria-labelledby=\"tab-2\" hidden>\n  <!-- Panel content -->\n</div>\n```\n\n### Live regions (4.1.3)\n\n```html\n<!-- Status updates -->\n<div aria-live=\"polite\" aria-atomic=\"true\" class=\"status\">\n  <!-- Content updates announced to screen readers -->\n</div>\n\n<!-- Urgent alerts -->\n<div role=\"alert\" aria-live=\"assertive\">\n  <!-- Interrupts current announcement -->\n</div>\n```\n\n```javascript\n// Announce dynamic content changes\nfunction showNotification(message, type = 'polite') {\n  const container = document.getElementById(`${type}-announcer`);\n  container.textContent = ''; // Clear first\n  requestAnimationFrame(() => {\n    container.textContent = message;\n  });\n}\n```\n\n---\n\n## Testing checklist\n\n### Automated testing\n```bash\n# Lighthouse accessibility audit\nnpx lighthouse https://example.com --only-categories=accessibility\n\n# axe-core\nnpm install @axe-core/cli -g\naxe https://example.com\n```\n\n### Manual testing\n\n- [ ] **Keyboard navigation:** Tab through entire page, use Enter/Space to activate\n- [ ] **Screen reader:** Test with VoiceOver (Mac), NVDA (Windows), or TalkBack (Android)\n- [ ] **Zoom:** Content usable at 200% zoom\n- [ ] **High contrast:** Test with Windows High Contrast Mode\n- [ ] **Reduced motion:** Test with `prefers-reduced-motion: reduce`\n- [ ] **Focus order:** Logical and follows visual order\n\n### Screen reader commands\n\n| Action | VoiceOver (Mac) | NVDA (Windows) |\n|--------|-----------------|----------------|\n| Start/Stop | ⌘ + F5 | Ctrl + Alt + N |\n| Next item | VO + → | ↓ |\n| Previous item | VO + ← | ↑ |\n| Activate | VO + Space | Enter |\n| Headings list | VO + U, then arrows | H / Shift + H |\n| Links list | VO + U | K / Shift + K |\n\n---\n\n## Common issues by impact\n\n### Critical (fix immediately)\n1. Missing form labels\n2. Missing image alt text\n3. Insufficient color contrast\n4. Keyboard traps\n5. No focus indicators\n\n### Serious (fix before launch)\n1. Missing page language\n2. Missing heading structure\n3. Non-descriptive link text\n4. Auto-playing media\n5. Missing skip links\n\n### Moderate (fix soon)\n1. Missing ARIA labels on icons\n2. Inconsistent navigation\n3. Missing error identification\n4. Timing without controls\n5. Missing landmark regions\n\n## References\n\n- [WCAG 2.1 Quick Reference](https://www.w3.org/WAI/WCAG21/quickref/)\n- [WAI-ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/)\n- [Deque axe Rules](https://dequeuniversity.com/rules/axe/)\n- [Web Quality Audit](../web-quality-audit/SKILL.md)\n\n<!-- File: src/resources/skills/agent-browser/references/authentication.md (Tokens: ~1188 | Category: anthropic-skill) -->\n# Authentication Patterns\n\nLogin flows, session persistence, OAuth, 2FA, and authenticated browsing.\n\n**Related**: [session-management.md](session-management.md) for state persistence details, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Login Flow](#basic-login-flow)\n- [Saving Authentication State](#saving-authentication-state)\n- [Restoring Authentication](#restoring-authentication)\n- [OAuth / SSO Flows](#oauth--sso-flows)\n- [Two-Factor Authentication](#two-factor-authentication)\n- [HTTP Basic Auth](#http-basic-auth)\n- [Cookie-Based Auth](#cookie-based-auth)\n- [Token Refresh Handling](#token-refresh-handling)\n- [Security Best Practices](#security-best-practices)\n\n## Basic Login Flow\n\n```bash\n# Navigate to login page\nagent-browser open https://app.example.com/login\nagent-browser wait --load networkidle\n\n# Get form elements\nagent-browser snapshot -i\n# Output: @e1 [input type=\"email\"], @e2 [input type=\"password\"], @e3 [button] \"Sign In\"\n\n# Fill credentials\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\n\n# Submit\nagent-browser click @e3\nagent-browser wait --load networkidle\n\n# Verify login succeeded\nagent-browser get url  # Should be dashboard, not login\n```\n\n## Saving Authentication State\n\nAfter logging in, save state for reuse:\n\n```bash\n# Login first (see above)\nagent-browser open https://app.example.com/login\nagent-browser snapshot -i\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\nagent-browser click @e3\nagent-browser wait --url \"**/dashboard\"\n\n# Save authenticated state\nagent-browser state save ./auth-state.json\n```\n\n## Restoring Authentication\n\nSkip login by loading saved state:\n\n```bash\n# Load saved auth state\nagent-browser state load ./auth-state.json\n\n# Navigate directly to protected page\nagent-browser open https://app.example.com/dashboard\n\n# Verify authenticated\nagent-browser snapshot -i\n```\n\n## OAuth / SSO Flows\n\nFor OAuth redirects:\n\n```bash\n# Start OAuth flow\nagent-browser open https://app.example.com/auth/google\n\n# Handle redirects automatically\nagent-browser wait --url \"**/accounts.google.com**\"\nagent-browser snapshot -i\n\n# Fill Google credentials\nagent-browser fill @e1 \"user@gmail.com\"\nagent-browser click @e2  # Next button\nagent-browser wait 2000\nagent-browser snapshot -i\nagent-browser fill @e3 \"password\"\nagent-browser click @e4  # Sign in\n\n# Wait for redirect back\nagent-browser wait --url \"**/app.example.com**\"\nagent-browser state save ./oauth-state.json\n```\n\n## Two-Factor Authentication\n\nHandle 2FA with manual intervention:\n\n```bash\n# Login with credentials\nagent-browser open https://app.example.com/login --headed  # Show browser\nagent-browser snapshot -i\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\nagent-browser click @e3\n\n# Wait for user to complete 2FA manually\necho \"Complete 2FA in the browser window...\"\nagent-browser wait --url \"**/dashboard\" --timeout 120000\n\n# Save state after 2FA\nagent-browser state save ./2fa-state.json\n```\n\n## HTTP Basic Auth\n\nFor sites using HTTP Basic Authentication:\n\n```bash\n# Set credentials before navigation\nagent-browser set credentials username password\n\n# Navigate to protected resource\nagent-browser open https://protected.example.com/api\n```\n\n## Cookie-Based Auth\n\nManually set authentication cookies:\n\n```bash\n# Set auth cookie\nagent-browser cookies set session_token \"abc123xyz\"\n\n# Navigate to protected page\nagent-browser open https://app.example.com/dashboard\n```\n\n## Token Refresh Handling\n\nFor sessions with expiring tokens:\n\n```bash\n#!/bin/bash\n# Wrapper that handles token refresh\n\nSTATE_FILE=\"./auth-state.json\"\n\n# Try loading existing state\nif [[ -f \"$STATE_FILE\" ]]; then\n    agent-browser state load \"$STATE_FILE\"\n    agent-browser open https://app.example.com/dashboard\n\n    # Check if session is still valid\n    URL=$(agent-browser get url)\n    if [[ \"$URL\" == *\"/login\"* ]]; then\n        echo \"Session expired, re-authenticating...\"\n        # Perform fresh login\n        agent-browser snapshot -i\n        agent-browser fill @e1 \"$USERNAME\"\n        agent-browser fill @e2 \"$PASSWORD\"\n        agent-browser click @e3\n        agent-browser wait --url \"**/dashboard\"\n        agent-browser state save \"$STATE_FILE\"\n    fi\nelse\n    # First-time login\n    agent-browser open https://app.example.com/login\n    # ... login flow ...\nfi\n```\n\n## Security Best Practices\n\n1. **Never commit state files** - They contain session tokens\n   ```bash\n   echo \"*.auth-state.json\" >> .gitignore\n   ```\n\n2. **Use environment variables for credentials**\n   ```bash\n   agent-browser fill @e1 \"$APP_USERNAME\"\n   agent-browser fill @e2 \"$APP_PASSWORD\"\n   ```\n\n3. **Clean up after automation**\n   ```bash\n   agent-browser cookies clear\n   rm -f ./auth-state.json\n   ```\n\n4. **Use short-lived sessions for CI/CD**\n   ```bash\n   # Don't persist state in CI\n   agent-browser open https://app.example.com/login\n   # ... login and perform actions ...\n   agent-browser close  # Session ends, nothing persisted\n   ```\n\n<!-- File: src/resources/skills/agent-browser/references/commands.md (Tokens: ~2205 | Category: anthropic-skill) -->\n# Command Reference\n\nComplete reference for all agent-browser commands. For quick start and common patterns, see SKILL.md.\n\n## Navigation\n\n```bash\nagent-browser open <url>      # Navigate to URL (aliases: goto, navigate)\n                              # Supports: https://, http://, file://, about:, data://\n                              # Auto-prepends https:// if no protocol given\nagent-browser back            # Go back\nagent-browser forward         # Go forward\nagent-browser reload          # Reload page\nagent-browser close           # Close browser (aliases: quit, exit)\nagent-browser connect 9222    # Connect to browser via CDP port\n```\n\n## Snapshot (page analysis)\n\n```bash\nagent-browser snapshot            # Full accessibility tree\nagent-browser snapshot -i         # Interactive elements only (recommended)\nagent-browser snapshot -c         # Compact output\nagent-browser snapshot -d 3       # Limit depth to 3\nagent-browser snapshot -s \"#main\" # Scope to CSS selector\n```\n\n## Interactions (use @refs from snapshot)\n\n```bash\nagent-browser click @e1           # Click\nagent-browser click @e1 --new-tab # Click and open in new tab\nagent-browser dblclick @e1        # Double-click\nagent-browser focus @e1           # Focus element\nagent-browser fill @e2 \"text\"     # Clear and type\nagent-browser type @e2 \"text\"     # Type without clearing\nagent-browser press Enter         # Press key (alias: key)\nagent-browser press Control+a     # Key combination\nagent-browser keydown Shift       # Hold key down\nagent-browser keyup Shift         # Release key\nagent-browser hover @e1           # Hover\nagent-browser check @e1           # Check checkbox\nagent-browser uncheck @e1         # Uncheck checkbox\nagent-browser select @e1 \"value\"  # Select dropdown option\nagent-browser select @e1 \"a\" \"b\"  # Select multiple options\nagent-browser scroll down 500     # Scroll page (default: down 300px)\nagent-browser scrollintoview @e1  # Scroll element into view (alias: scrollinto)\nagent-browser drag @e1 @e2        # Drag and drop\nagent-browser upload @e1 file.pdf # Upload files\n```\n\n## Get Information\n\n```bash\nagent-browser get text @e1        # Get element text\nagent-browser get html @e1        # Get innerHTML\nagent-browser get value @e1       # Get input value\nagent-browser get attr @e1 href   # Get attribute\nagent-browser get title           # Get page title\nagent-browser get url             # Get current URL\nagent-browser get count \".item\"   # Count matching elements\nagent-browser get box @e1         # Get bounding box\nagent-browser get styles @e1      # Get computed styles (font, color, bg, etc.)\n```\n\n## Check State\n\n```bash\nagent-browser is visible @e1      # Check if visible\nagent-browser is enabled @e1      # Check if enabled\nagent-browser is checked @e1      # Check if checked\n```\n\n## Screenshots and PDF\n\n```bash\nagent-browser screenshot          # Save to temporary directory\nagent-browser screenshot path.png # Save to specific path\nagent-browser screenshot --full   # Full page\nagent-browser pdf output.pdf      # Save as PDF\n```\n\n## Video Recording\n\n```bash\nagent-browser record start ./demo.webm    # Start recording\nagent-browser click @e1                   # Perform actions\nagent-browser record stop                 # Stop and save video\nagent-browser record restart ./take2.webm # Stop current + start new\n```\n\n## Wait\n\n```bash\nagent-browser wait @e1                     # Wait for element\nagent-browser wait 2000                    # Wait milliseconds\nagent-browser wait --text \"Success\"        # Wait for text (or -t)\nagent-browser wait --url \"**/dashboard\"    # Wait for URL pattern (or -u)\nagent-browser wait --load networkidle      # Wait for network idle (or -l)\nagent-browser wait --fn \"window.ready\"     # Wait for JS condition (or -f)\n```\n\n## Mouse Control\n\n```bash\nagent-browser mouse move 100 200      # Move mouse\nagent-browser mouse down left         # Press button\nagent-browser mouse up left           # Release button\nagent-browser mouse wheel 100         # Scroll wheel\n```\n\n## Semantic Locators (alternative to refs)\n\n```bash\nagent-browser find role button click --name \"Submit\"\nagent-browser find text \"Sign In\" click\nagent-browser find text \"Sign In\" click --exact      # Exact match only\nagent-browser find label \"Email\" fill \"user@test.com\"\nagent-browser find placeholder \"Search\" type \"query\"\nagent-browser find alt \"Logo\" click\nagent-browser find title \"Close\" click\nagent-browser find testid \"submit-btn\" click\nagent-browser find first \".item\" click\nagent-browser find last \".item\" click\nagent-browser find nth 2 \"a\" hover\n```\n\n## Browser Settings\n\n```bash\nagent-browser set viewport 1920 1080          # Set viewport size\nagent-browser set device \"iPhone 14\"          # Emulate device\nagent-browser set geo 37.7749 -122.4194       # Set geolocation (alias: geolocation)\nagent-browser set offline on                  # Toggle offline mode\nagent-browser set headers '{\"X-Key\":\"v\"}'     # Extra HTTP headers\nagent-browser set credentials user pass       # HTTP basic auth (alias: auth)\nagent-browser set media dark                  # Emulate color scheme\nagent-browser set media light reduced-motion  # Light mode + reduced motion\n```\n\n## Cookies and Storage\n\n```bash\nagent-browser cookies                     # Get all cookies\nagent-browser cookies set name value      # Set cookie\nagent-browser cookies clear               # Clear cookies\nagent-browser storage local               # Get all localStorage\nagent-browser storage local key           # Get specific key\nagent-browser storage local set k v       # Set value\nagent-browser storage local clear         # Clear all\n```\n\n## Network\n\n```bash\nagent-browser network route <url>              # Intercept requests\nagent-browser network route <url> --abort      # Block requests\nagent-browser network route <url> --body '{}'  # Mock response\nagent-browser network unroute [url]            # Remove routes\nagent-browser network requests                 # View tracked requests\nagent-browser network requests --filter api    # Filter requests\n```\n\n## Tabs and Windows\n\n```bash\nagent-browser tab                 # List tabs\nagent-browser tab new [url]       # New tab\nagent-browser tab 2               # Switch to tab by index\nagent-browser tab close           # Close current tab\nagent-browser tab close 2         # Close tab by index\nagent-browser window new          # New window\n```\n\n## Frames\n\n```bash\nagent-browser frame \"#iframe\"     # Switch to iframe\nagent-browser frame main          # Back to main frame\n```\n\n## Dialogs\n\n```bash\nagent-browser dialog accept [text]  # Accept dialog\nagent-browser dialog dismiss        # Dismiss dialog\n```\n\n## JavaScript\n\n```bash\nagent-browser eval \"document.title\"          # Simple expressions only\nagent-browser eval -b \"<base64>\"             # Any JavaScript (base64 encoded)\nagent-browser eval --stdin                   # Read script from stdin\n```\n\nUse `-b`/`--base64` or `--stdin` for reliable execution. Shell escaping with nested quotes and special characters is error-prone.\n\n```bash\n# Base64 encode your script, then:\nagent-browser eval -b \"ZG9jdW1lbnQucXVlcnlTZWxlY3RvcignW3NyYyo9Il9uZXh0Il0nKQ==\"\n\n# Or use stdin with heredoc for multiline scripts:\ncat <<'EOF' | agent-browser eval --stdin\nconst links = document.querySelectorAll('a');\nArray.from(links).map(a => a.href);\nEOF\n```\n\n## State Management\n\n```bash\nagent-browser state save auth.json    # Save cookies, storage, auth state\nagent-browser state load auth.json    # Restore saved state\n```\n\n## Global Options\n\n```bash\nagent-browser --session <name> ...    # Isolated browser session\nagent-browser --json ...              # JSON output for parsing\nagent-browser --headed ...            # Show browser window (not headless)\nagent-browser --full ...              # Full page screenshot (-f)\nagent-browser --cdp <port> ...        # Connect via Chrome DevTools Protocol\nagent-browser -p <provider> ...       # Cloud browser provider (--provider)\nagent-browser --proxy <url> ...       # Use proxy server\nagent-browser --proxy-bypass <hosts>  # Hosts to bypass proxy\nagent-browser --headers <json> ...    # HTTP headers scoped to URL's origin\nagent-browser --executable-path <p>   # Custom browser executable\nagent-browser --extension <path> ...  # Load browser extension (repeatable)\nagent-browser --ignore-https-errors   # Ignore SSL certificate errors\nagent-browser --help                  # Show help (-h)\nagent-browser --version               # Show version (-V)\nagent-browser <command> --help        # Show detailed help for a command\n```\n\n## Debugging\n\n```bash\nagent-browser --headed open example.com   # Show browser window\nagent-browser --cdp 9222 snapshot         # Connect via CDP port\nagent-browser connect 9222                # Alternative: connect command\nagent-browser console                     # View console messages\nagent-browser console --clear             # Clear console\nagent-browser errors                      # View page errors\nagent-browser errors --clear              # Clear errors\nagent-browser highlight @e1               # Highlight element\nagent-browser trace start                 # Start recording trace\nagent-browser trace stop trace.zip        # Stop and save trace\nagent-browser profiler start              # Start Chrome DevTools profiling\nagent-browser profiler stop trace.json    # Stop and save profile\n```\n\n## Environment Variables\n\n```bash\nAGENT_BROWSER_SESSION=\"mysession\"            # Default session name\nAGENT_BROWSER_EXECUTABLE_PATH=\"/path/chrome\" # Custom browser path\nAGENT_BROWSER_EXTENSIONS=\"/ext1,/ext2\"       # Comma-separated extension paths\nAGENT_BROWSER_PROVIDER=\"browserbase\"         # Cloud browser provider\nAGENT_BROWSER_STREAM_PORT=\"9223\"             # WebSocket streaming port\nAGENT_BROWSER_HOME=\"/path/to/agent-browser\"  # Custom install location\n```\n\n<!-- File: src/resources/skills/agent-browser/references/profiling.md (Tokens: ~788 | Category: anthropic-skill) -->\n# Profiling\n\nCapture Chrome DevTools performance profiles during browser automation for performance analysis.\n\n**Related**: [commands.md](commands.md) for full command reference, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Profiling](#basic-profiling)\n- [Profiler Commands](#profiler-commands)\n- [Categories](#categories)\n- [Use Cases](#use-cases)\n- [Output Format](#output-format)\n- [Viewing Profiles](#viewing-profiles)\n- [Limitations](#limitations)\n\n## Basic Profiling\n\n```bash\n# Start profiling\nagent-browser profiler start\n\n# Perform actions\nagent-browser navigate https://example.com\nagent-browser click \"#button\"\nagent-browser wait 1000\n\n# Stop and save\nagent-browser profiler stop ./trace.json\n```\n\n## Profiler Commands\n\n```bash\n# Start profiling with default categories\nagent-browser profiler start\n\n# Start with custom trace categories\nagent-browser profiler start --categories \"devtools.timeline,v8.execute,blink.user_timing\"\n\n# Stop profiling and save to file\nagent-browser profiler stop ./trace.json\n```\n\n## Categories\n\nThe `--categories` flag accepts a comma-separated list of Chrome trace categories. Default categories include:\n\n- `devtools.timeline` -- standard DevTools performance traces\n- `v8.execute` -- time spent running JavaScript\n- `blink` -- renderer events\n- `blink.user_timing` -- `performance.mark()` / `performance.measure()` calls\n- `latencyInfo` -- input-to-latency tracking\n- `renderer.scheduler` -- task scheduling and execution\n- `toplevel` -- broad-spectrum basic events\n\nSeveral `disabled-by-default-*` categories are also included for detailed timeline, call stack, and V8 CPU profiling data.\n\n## Use Cases\n\n### Diagnosing Slow Page Loads\n\n```bash\nagent-browser profiler start\nagent-browser navigate https://app.example.com\nagent-browser wait --load networkidle\nagent-browser profiler stop ./page-load-profile.json\n```\n\n### Profiling User Interactions\n\n```bash\nagent-browser navigate https://app.example.com\nagent-browser profiler start\nagent-browser click \"#submit\"\nagent-browser wait 2000\nagent-browser profiler stop ./interaction-profile.json\n```\n\n### CI Performance Regression Checks\n\n```bash\n#!/bin/bash\nagent-browser profiler start\nagent-browser navigate https://app.example.com\nagent-browser wait --load networkidle\nagent-browser profiler stop \"./profiles/build-${BUILD_ID}.json\"\n```\n\n## Output Format\n\nThe output is a JSON file in Chrome Trace Event format:\n\n```json\n{\n  \"traceEvents\": [\n    { \"cat\": \"devtools.timeline\", \"name\": \"RunTask\", \"ph\": \"X\", \"ts\": 12345, \"dur\": 100, ... },\n    ...\n  ],\n  \"metadata\": {\n    \"clock-domain\": \"LINUX_CLOCK_MONOTONIC\"\n  }\n}\n```\n\nThe `metadata.clock-domain` field is set based on the host platform (Linux or macOS). On Windows it is omitted.\n\n## Viewing Profiles\n\nLoad the output JSON file in any of these tools:\n\n- **Chrome DevTools**: Performance panel > Load profile (Ctrl+Shift+I > Performance)\n- **Perfetto UI**: https://ui.perfetto.dev/ -- drag and drop the JSON file\n- **Trace Viewer**: `chrome://tracing` in any Chromium browser\n\n## Limitations\n\n- Only works with Chromium-based browsers (Chrome, Edge). Not supported on Firefox or WebKit.\n- Trace data accumulates in memory while profiling is active (capped at 5 million events). Stop profiling promptly after the area of interest.\n- Data collection on stop has a 30-second timeout. If the browser is unresponsive, the stop command may fail.\n\n<!-- File: src/resources/skills/agent-browser/references/proxy-support.md (Tokens: ~1248 | Category: anthropic-skill) -->\n# Proxy Support\n\nProxy configuration for geo-testing, rate limiting avoidance, and corporate environments.\n\n**Related**: [commands.md](commands.md) for global options, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Proxy Configuration](#basic-proxy-configuration)\n- [Authenticated Proxy](#authenticated-proxy)\n- [SOCKS Proxy](#socks-proxy)\n- [Proxy Bypass](#proxy-bypass)\n- [Common Use Cases](#common-use-cases)\n- [Verifying Proxy Connection](#verifying-proxy-connection)\n- [Troubleshooting](#troubleshooting)\n- [Best Practices](#best-practices)\n\n## Basic Proxy Configuration\n\nUse the `--proxy` flag or set proxy via environment variable:\n\n```bash\n# Via CLI flag\nagent-browser --proxy \"http://proxy.example.com:8080\" open https://example.com\n\n# Via environment variable\nexport HTTP_PROXY=\"http://proxy.example.com:8080\"\nagent-browser open https://example.com\n\n# HTTPS proxy\nexport HTTPS_PROXY=\"https://proxy.example.com:8080\"\nagent-browser open https://example.com\n\n# Both\nexport HTTP_PROXY=\"http://proxy.example.com:8080\"\nexport HTTPS_PROXY=\"http://proxy.example.com:8080\"\nagent-browser open https://example.com\n```\n\n## Authenticated Proxy\n\nFor proxies requiring authentication:\n\n```bash\n# Include credentials in URL\nexport HTTP_PROXY=\"http://username:password@proxy.example.com:8080\"\nagent-browser open https://example.com\n```\n\n## SOCKS Proxy\n\n```bash\n# SOCKS5 proxy\nexport ALL_PROXY=\"socks5://proxy.example.com:1080\"\nagent-browser open https://example.com\n\n# SOCKS5 with auth\nexport ALL_PROXY=\"socks5://user:pass@proxy.example.com:1080\"\nagent-browser open https://example.com\n```\n\n## Proxy Bypass\n\nSkip proxy for specific domains using `--proxy-bypass` or `NO_PROXY`:\n\n```bash\n# Via CLI flag\nagent-browser --proxy \"http://proxy.example.com:8080\" --proxy-bypass \"localhost,*.internal.com\" open https://example.com\n\n# Via environment variable\nexport NO_PROXY=\"localhost,127.0.0.1,.internal.company.com\"\nagent-browser open https://internal.company.com  # Direct connection\nagent-browser open https://external.com          # Via proxy\n```\n\n## Common Use Cases\n\n### Geo-Location Testing\n\n```bash\n#!/bin/bash\n# Test site from different regions using geo-located proxies\n\nPROXIES=(\n    \"http://us-proxy.example.com:8080\"\n    \"http://eu-proxy.example.com:8080\"\n    \"http://asia-proxy.example.com:8080\"\n)\n\nfor proxy in \"${PROXIES[@]}\"; do\n    export HTTP_PROXY=\"$proxy\"\n    export HTTPS_PROXY=\"$proxy\"\n\n    region=$(echo \"$proxy\" | grep -oP '^\\w+-\\w+')\n    echo \"Testing from: $region\"\n\n    agent-browser --session \"$region\" open https://example.com\n    agent-browser --session \"$region\" screenshot \"./screenshots/$region.png\"\n    agent-browser --session \"$region\" close\ndone\n```\n\n### Rotating Proxies for Scraping\n\n```bash\n#!/bin/bash\n# Rotate through proxy list to avoid rate limiting\n\nPROXY_LIST=(\n    \"http://proxy1.example.com:8080\"\n    \"http://proxy2.example.com:8080\"\n    \"http://proxy3.example.com:8080\"\n)\n\nURLS=(\n    \"https://site.com/page1\"\n    \"https://site.com/page2\"\n    \"https://site.com/page3\"\n)\n\nfor i in \"${!URLS[@]}\"; do\n    proxy_index=$((i % ${#PROXY_LIST[@]}))\n    export HTTP_PROXY=\"${PROXY_LIST[$proxy_index]}\"\n    export HTTPS_PROXY=\"${PROXY_LIST[$proxy_index]}\"\n\n    agent-browser open \"${URLS[$i]}\"\n    agent-browser get text body > \"output-$i.txt\"\n    agent-browser close\n\n    sleep 1  # Polite delay\ndone\n```\n\n### Corporate Network Access\n\n```bash\n#!/bin/bash\n# Access internal sites via corporate proxy\n\nexport HTTP_PROXY=\"http://corpproxy.company.com:8080\"\nexport HTTPS_PROXY=\"http://corpproxy.company.com:8080\"\nexport NO_PROXY=\"localhost,127.0.0.1,.company.com\"\n\n# External sites go through proxy\nagent-browser open https://external-vendor.com\n\n# Internal sites bypass proxy\nagent-browser open https://intranet.company.com\n```\n\n## Verifying Proxy Connection\n\n```bash\n# Check your apparent IP\nagent-browser open https://httpbin.org/ip\nagent-browser get text body\n# Should show proxy's IP, not your real IP\n```\n\n## Troubleshooting\n\n### Proxy Connection Failed\n\n```bash\n# Test proxy connectivity first\ncurl -x http://proxy.example.com:8080 https://httpbin.org/ip\n\n# Check if proxy requires auth\nexport HTTP_PROXY=\"http://user:pass@proxy.example.com:8080\"\n```\n\n### SSL/TLS Errors Through Proxy\n\nSome proxies perform SSL inspection. If you encounter certificate errors:\n\n```bash\n# For testing only - not recommended for production\nagent-browser open https://example.com --ignore-https-errors\n```\n\n### Slow Performance\n\n```bash\n# Use proxy only when necessary\nexport NO_PROXY=\"*.cdn.com,*.static.com\"  # Direct CDN access\n```\n\n## Best Practices\n\n1. **Use environment variables** - Don't hardcode proxy credentials\n2. **Set NO_PROXY appropriately** - Avoid routing local traffic through proxy\n3. **Test proxy before automation** - Verify connectivity with simple requests\n4. **Handle proxy failures gracefully** - Implement retry logic for unstable proxies\n5. **Rotate proxies for large scraping jobs** - Distribute load and avoid bans\n\n<!-- File: src/resources/skills/agent-browser/references/session-management.md (Tokens: ~1017 | Category: anthropic-skill) -->\n# Session Management\n\nMultiple isolated browser sessions with state persistence and concurrent browsing.\n\n**Related**: [authentication.md](authentication.md) for login patterns, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Named Sessions](#named-sessions)\n- [Session Isolation Properties](#session-isolation-properties)\n- [Session State Persistence](#session-state-persistence)\n- [Common Patterns](#common-patterns)\n- [Default Session](#default-session)\n- [Session Cleanup](#session-cleanup)\n- [Best Practices](#best-practices)\n\n## Named Sessions\n\nUse `--session` flag to isolate browser contexts:\n\n```bash\n# Session 1: Authentication flow\nagent-browser --session auth open https://app.example.com/login\n\n# Session 2: Public browsing (separate cookies, storage)\nagent-browser --session public open https://example.com\n\n# Commands are isolated by session\nagent-browser --session auth fill @e1 \"user@example.com\"\nagent-browser --session public get text body\n```\n\n## Session Isolation Properties\n\nEach session has independent:\n- Cookies\n- LocalStorage / SessionStorage\n- IndexedDB\n- Cache\n- Browsing history\n- Open tabs\n\n## Session State Persistence\n\n### Save Session State\n\n```bash\n# Save cookies, storage, and auth state\nagent-browser state save /path/to/auth-state.json\n```\n\n### Load Session State\n\n```bash\n# Restore saved state\nagent-browser state load /path/to/auth-state.json\n\n# Continue with authenticated session\nagent-browser open https://app.example.com/dashboard\n```\n\n### State File Contents\n\n```json\n{\n  \"cookies\": [...],\n  \"localStorage\": {...},\n  \"sessionStorage\": {...},\n  \"origins\": [...]\n}\n```\n\n## Common Patterns\n\n### Authenticated Session Reuse\n\n```bash\n#!/bin/bash\n# Save login state once, reuse many times\n\nSTATE_FILE=\"/tmp/auth-state.json\"\n\n# Check if we have saved state\nif [[ -f \"$STATE_FILE\" ]]; then\n    agent-browser state load \"$STATE_FILE\"\n    agent-browser open https://app.example.com/dashboard\nelse\n    # Perform login\n    agent-browser open https://app.example.com/login\n    agent-browser snapshot -i\n    agent-browser fill @e1 \"$USERNAME\"\n    agent-browser fill @e2 \"$PASSWORD\"\n    agent-browser click @e3\n    agent-browser wait --load networkidle\n\n    # Save for future use\n    agent-browser state save \"$STATE_FILE\"\nfi\n```\n\n### Concurrent Scraping\n\n```bash\n#!/bin/bash\n# Scrape multiple sites concurrently\n\n# Start all sessions\nagent-browser --session site1 open https://site1.com &\nagent-browser --session site2 open https://site2.com &\nagent-browser --session site3 open https://site3.com &\nwait\n\n# Extract from each\nagent-browser --session site1 get text body > site1.txt\nagent-browser --session site2 get text body > site2.txt\nagent-browser --session site3 get text body > site3.txt\n\n# Cleanup\nagent-browser --session site1 close\nagent-browser --session site2 close\nagent-browser --session site3 close\n```\n\n### A/B Testing Sessions\n\n```bash\n# Test different user experiences\nagent-browser --session variant-a open \"https://app.com?variant=a\"\nagent-browser --session variant-b open \"https://app.com?variant=b\"\n\n# Compare\nagent-browser --session variant-a screenshot /tmp/variant-a.png\nagent-browser --session variant-b screenshot /tmp/variant-b.png\n```\n\n## Default Session\n\nWhen `--session` is omitted, commands use the default session:\n\n```bash\n# These use the same default session\nagent-browser open https://example.com\nagent-browser snapshot -i\nagent-browser close  # Closes default session\n```\n\n## Session Cleanup\n\n```bash\n# Close specific session\nagent-browser --session auth close\n\n# List active sessions\nagent-browser session list\n```\n\n## Best Practices\n\n### 1. Name Sessions Semantically\n\n```bash\n# GOOD: Clear purpose\nagent-browser --session github-auth open https://github.com\nagent-browser --session docs-scrape open https://docs.example.com\n\n# AVOID: Generic names\nagent-browser --session s1 open https://github.com\n```\n\n### 2. Always Clean Up\n\n```bash\n# Close sessions when done\nagent-browser --session auth close\nagent-browser --session scrape close\n```\n\n### 3. Handle State Files Securely\n\n```bash\n# Don't commit state files (contain auth tokens!)\necho \"*.auth-state.json\" >> .gitignore\n\n# Delete after use\nrm /tmp/auth-state.json\n```\n\n### 4. Timeout Long Sessions\n\n```bash\n# Set timeout for automated scripts\ntimeout 60 agent-browser --session long-task get text body\n```\n\n<!-- File: src/resources/skills/agent-browser/references/snapshot-refs.md (Tokens: ~1129 | Category: anthropic-skill) -->\n# Snapshot and Refs\n\nCompact element references that reduce context usage dramatically for AI agents.\n\n**Related**: [commands.md](commands.md) for full command reference, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [How Refs Work](#how-refs-work)\n- [Snapshot Command](#the-snapshot-command)\n- [Using Refs](#using-refs)\n- [Ref Lifecycle](#ref-lifecycle)\n- [Best Practices](#best-practices)\n- [Ref Notation Details](#ref-notation-details)\n- [Troubleshooting](#troubleshooting)\n\n## How Refs Work\n\nTraditional approach:\n```\nFull DOM/HTML → AI parses → CSS selector → Action (~3000-5000 tokens)\n```\n\nagent-browser approach:\n```\nCompact snapshot → @refs assigned → Direct interaction (~200-400 tokens)\n```\n\n## The Snapshot Command\n\n```bash\n# Basic snapshot (shows page structure)\nagent-browser snapshot\n\n# Interactive snapshot (-i flag) - RECOMMENDED\nagent-browser snapshot -i\n```\n\n### Snapshot Output Format\n\n```\nPage: Example Site - Home\nURL: https://example.com\n\n@e1 [header]\n  @e2 [nav]\n    @e3 [a] \"Home\"\n    @e4 [a] \"Products\"\n    @e5 [a] \"About\"\n  @e6 [button] \"Sign In\"\n\n@e7 [main]\n  @e8 [h1] \"Welcome\"\n  @e9 [form]\n    @e10 [input type=\"email\"] placeholder=\"Email\"\n    @e11 [input type=\"password\"] placeholder=\"Password\"\n    @e12 [button type=\"submit\"] \"Log In\"\n\n@e13 [footer]\n  @e14 [a] \"Privacy Policy\"\n```\n\n## Using Refs\n\nOnce you have refs, interact directly:\n\n```bash\n# Click the \"Sign In\" button\nagent-browser click @e6\n\n# Fill email input\nagent-browser fill @e10 \"user@example.com\"\n\n# Fill password\nagent-browser fill @e11 \"password123\"\n\n# Submit the form\nagent-browser click @e12\n```\n\n## Ref Lifecycle\n\n**IMPORTANT**: Refs are invalidated when the page changes!\n\n```bash\n# Get initial snapshot\nagent-browser snapshot -i\n# @e1 [button] \"Next\"\n\n# Click triggers page change\nagent-browser click @e1\n\n# MUST re-snapshot to get new refs!\nagent-browser snapshot -i\n# @e1 [h1] \"Page 2\"  ← Different element now!\n```\n\n## Best Practices\n\n### 1. Always Snapshot Before Interacting\n\n```bash\n# CORRECT\nagent-browser open https://example.com\nagent-browser snapshot -i          # Get refs first\nagent-browser click @e1            # Use ref\n\n# WRONG\nagent-browser open https://example.com\nagent-browser click @e1            # Ref doesn't exist yet!\n```\n\n### 2. Re-Snapshot After Navigation\n\n```bash\nagent-browser click @e5            # Navigates to new page\nagent-browser snapshot -i          # Get new refs\nagent-browser click @e1            # Use new refs\n```\n\n### 3. Re-Snapshot After Dynamic Changes\n\n```bash\nagent-browser click @e1            # Opens dropdown\nagent-browser snapshot -i          # See dropdown items\nagent-browser click @e7            # Select item\n```\n\n### 4. Snapshot Specific Regions\n\nFor complex pages, snapshot specific areas:\n\n```bash\n# Snapshot just the form\nagent-browser snapshot @e9\n```\n\n## Ref Notation Details\n\n```\n@e1 [tag type=\"value\"] \"text content\" placeholder=\"hint\"\n│    │   │             │               │\n│    │   │             │               └─ Additional attributes\n│    │   │             └─ Visible text\n│    │   └─ Key attributes shown\n│    └─ HTML tag name\n└─ Unique ref ID\n```\n\n### Common Patterns\n\n```\n@e1 [button] \"Submit\"                    # Button with text\n@e2 [input type=\"email\"]                 # Email input\n@e3 [input type=\"password\"]              # Password input\n@e4 [a href=\"/page\"] \"Link Text\"         # Anchor link\n@e5 [select]                             # Dropdown\n@e6 [textarea] placeholder=\"Message\"     # Text area\n@e7 [div class=\"modal\"]                  # Container (when relevant)\n@e8 [img alt=\"Logo\"]                     # Image\n@e9 [checkbox] checked                   # Checked checkbox\n@e10 [radio] selected                    # Selected radio\n```\n\n## Troubleshooting\n\n### \"Ref not found\" Error\n\n```bash\n# Ref may have changed - re-snapshot\nagent-browser snapshot -i\n```\n\n### Element Not Visible in Snapshot\n\n```bash\n# Scroll down to reveal element\nagent-browser scroll down 1000\nagent-browser snapshot -i\n\n# Or wait for dynamic content\nagent-browser wait 1000\nagent-browser snapshot -i\n```\n\n### Too Many Elements\n\n```bash\n# Snapshot specific container\nagent-browser snapshot @e5\n\n# Or use get text for content-only extraction\nagent-browser get text @e5\n```\n\n<!-- File: src/resources/skills/agent-browser/references/video-recording.md (Tokens: ~880 | Category: anthropic-skill) -->\n# Video Recording\n\nCapture browser automation as video for debugging, documentation, or verification.\n\n**Related**: [commands.md](commands.md) for full command reference, [SKILL.md](../SKILL.md) for quick start.\n\n## Contents\n\n- [Basic Recording](#basic-recording)\n- [Recording Commands](#recording-commands)\n- [Use Cases](#use-cases)\n- [Best Practices](#best-practices)\n- [Output Format](#output-format)\n- [Limitations](#limitations)\n\n## Basic Recording\n\n```bash\n# Start recording\nagent-browser record start ./demo.webm\n\n# Perform actions\nagent-browser open https://example.com\nagent-browser snapshot -i\nagent-browser click @e1\nagent-browser fill @e2 \"test input\"\n\n# Stop and save\nagent-browser record stop\n```\n\n## Recording Commands\n\n```bash\n# Start recording to file\nagent-browser record start ./output.webm\n\n# Stop current recording\nagent-browser record stop\n\n# Restart with new file (stops current + starts new)\nagent-browser record restart ./take2.webm\n```\n\n## Use Cases\n\n### Debugging Failed Automation\n\n```bash\n#!/bin/bash\n# Record automation for debugging\n\nagent-browser record start ./debug-$(date +%Y%m%d-%H%M%S).webm\n\n# Run your automation\nagent-browser open https://app.example.com\nagent-browser snapshot -i\nagent-browser click @e1 || {\n    echo \"Click failed - check recording\"\n    agent-browser record stop\n    exit 1\n}\n\nagent-browser record stop\n```\n\n### Documentation Generation\n\n```bash\n#!/bin/bash\n# Record workflow for documentation\n\nagent-browser record start ./docs/how-to-login.webm\n\nagent-browser open https://app.example.com/login\nagent-browser wait 1000  # Pause for visibility\n\nagent-browser snapshot -i\nagent-browser fill @e1 \"demo@example.com\"\nagent-browser wait 500\n\nagent-browser fill @e2 \"password\"\nagent-browser wait 500\n\nagent-browser click @e3\nagent-browser wait --load networkidle\nagent-browser wait 1000  # Show result\n\nagent-browser record stop\n```\n\n### CI/CD Test Evidence\n\n```bash\n#!/bin/bash\n# Record E2E test runs for CI artifacts\n\nTEST_NAME=\"${1:-e2e-test}\"\nRECORDING_DIR=\"./test-recordings\"\nmkdir -p \"$RECORDING_DIR\"\n\nagent-browser record start \"$RECORDING_DIR/$TEST_NAME-$(date +%s).webm\"\n\n# Run test\nif run_e2e_test; then\n    echo \"Test passed\"\nelse\n    echo \"Test failed - recording saved\"\nfi\n\nagent-browser record stop\n```\n\n## Best Practices\n\n### 1. Add Pauses for Clarity\n\n```bash\n# Slow down for human viewing\nagent-browser click @e1\nagent-browser wait 500  # Let viewer see result\n```\n\n### 2. Use Descriptive Filenames\n\n```bash\n# Include context in filename\nagent-browser record start ./recordings/login-flow-2024-01-15.webm\nagent-browser record start ./recordings/checkout-test-run-42.webm\n```\n\n### 3. Handle Recording in Error Cases\n\n```bash\n#!/bin/bash\nset -e\n\ncleanup() {\n    agent-browser record stop 2>/dev/null || true\n    agent-browser close 2>/dev/null || true\n}\ntrap cleanup EXIT\n\nagent-browser record start ./automation.webm\n# ... automation steps ...\n```\n\n### 4. Combine with Screenshots\n\n```bash\n# Record video AND capture key frames\nagent-browser record start ./flow.webm\n\nagent-browser open https://example.com\nagent-browser screenshot ./screenshots/step1-homepage.png\n\nagent-browser click @e1\nagent-browser screenshot ./screenshots/step2-after-click.png\n\nagent-browser record stop\n```\n\n## Output Format\n\n- Default format: WebM (VP8/VP9 codec)\n- Compatible with all modern browsers and video players\n- Compressed but high quality\n\n## Limitations\n\n- Recording adds slight overhead to automation\n- Large recordings can consume significant disk space\n- Some headless environments may have codec limitations\n\n<!-- File: src/resources/skills/agent-browser/SKILL.md (Tokens: ~4372 | Category: anthropic-skill) -->\n---\nname: agent-browser\ndescription: Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling forms, clicking buttons, taking screenshots, extracting data, testing web apps, or automating any browser task. Triggers include requests to \"open a website\", \"fill out a form\", \"click a button\", \"take a screenshot\", \"scrape data from a page\", \"test this web app\", \"login to a site\", \"automate browser actions\", or any task requiring programmatic web interaction.\nallowed-tools: Bash(npx agent-browser:*), Bash(agent-browser:*)\n---\n\n# Browser Automation with agent-browser\n\n## Core Workflow\n\nEvery browser automation follows this pattern:\n\n1. **Navigate**: `agent-browser open <url>`\n2. **Snapshot**: `agent-browser snapshot -i` (get element refs like `@e1`, `@e2`)\n3. **Interact**: Use refs to click, fill, select\n4. **Re-snapshot**: After navigation or DOM changes, get fresh refs\n\n```bash\nagent-browser open https://example.com/form\nagent-browser snapshot -i\n# Output: @e1 [input type=\"email\"], @e2 [input type=\"password\"], @e3 [button] \"Submit\"\n\nagent-browser fill @e1 \"user@example.com\"\nagent-browser fill @e2 \"password123\"\nagent-browser click @e3\nagent-browser wait --load networkidle\nagent-browser snapshot -i  # Check result\n```\n\n## Command Chaining\n\nCommands can be chained with `&&` in a single shell invocation. The browser persists between commands via a background daemon, so chaining is safe and more efficient than separate calls.\n\n```bash\n# Chain open + wait + snapshot in one call\nagent-browser open https://example.com && agent-browser wait --load networkidle && agent-browser snapshot -i\n\n# Chain multiple interactions\nagent-browser fill @e1 \"user@example.com\" && agent-browser fill @e2 \"password123\" && agent-browser click @e3\n\n# Navigate and capture\nagent-browser open https://example.com && agent-browser wait --load networkidle && agent-browser screenshot page.png\n```\n\n**When to chain:** Use `&&` when you don't need to read the output of an intermediate command before proceeding (e.g., open + wait + screenshot). Run commands separately when you need to parse the output first (e.g., snapshot to discover refs, then interact using those refs).\n\n## Essential Commands\n\n```bash\n# Navigation\nagent-browser open <url>              # Navigate (aliases: goto, navigate)\nagent-browser close                   # Close browser\n\n# Snapshot\nagent-browser snapshot -i             # Interactive elements with refs (recommended)\nagent-browser snapshot -i -C          # Include cursor-interactive elements (divs with onclick, cursor:pointer)\nagent-browser snapshot -s \"#selector\" # Scope to CSS selector\n\n# Interaction (use @refs from snapshot)\nagent-browser click @e1               # Click element\nagent-browser click @e1 --new-tab     # Click and open in new tab\nagent-browser fill @e2 \"text\"         # Clear and type text\nagent-browser type @e2 \"text\"         # Type without clearing\nagent-browser select @e1 \"option\"     # Select dropdown option\nagent-browser check @e1               # Check checkbox\nagent-browser press Enter             # Press key\nagent-browser keyboard type \"text\"    # Type at current focus (no selector)\nagent-browser keyboard inserttext \"text\"  # Insert without key events\nagent-browser scroll down 500         # Scroll page\nagent-browser scroll down 500 --selector \"div.content\"  # Scroll within a specific container\n\n# Get information\nagent-browser get text @e1            # Get element text\nagent-browser get url                 # Get current URL\nagent-browser get title               # Get page title\n\n# Wait\nagent-browser wait @e1                # Wait for element\nagent-browser wait --load networkidle # Wait for network idle\nagent-browser wait --url \"**/page\"    # Wait for URL pattern\nagent-browser wait 2000               # Wait milliseconds\n\n# Downloads\nagent-browser download @e1 ./file.pdf          # Click element to trigger download\nagent-browser wait --download ./output.zip     # Wait for any download to complete\nagent-browser --download-path ./downloads open <url>  # Set default download directory\n\n# Capture\nagent-browser screenshot              # Screenshot to temp dir\nagent-browser screenshot --full       # Full page screenshot\nagent-browser screenshot --annotate   # Annotated screenshot with numbered element labels\nagent-browser pdf output.pdf          # Save as PDF\n\n# Diff (compare page states)\nagent-browser diff snapshot                          # Compare current vs last snapshot\nagent-browser diff snapshot --baseline before.txt    # Compare current vs saved file\nagent-browser diff screenshot --baseline before.png  # Visual pixel diff\nagent-browser diff url <url1> <url2>                 # Compare two pages\nagent-browser diff url <url1> <url2> --wait-until networkidle  # Custom wait strategy\nagent-browser diff url <url1> <url2> --selector \"#main\"  # Scope to element\n```\n\n## Common Patterns\n\n### Form Submission\n\n```bash\nagent-browser open https://example.com/signup\nagent-browser snapshot -i\nagent-browser fill @e1 \"Jane Doe\"\nagent-browser fill @e2 \"jane@example.com\"\nagent-browser select @e3 \"California\"\nagent-browser check @e4\nagent-browser click @e5\nagent-browser wait --load networkidle\n```\n\n### Authentication with Auth Vault (Recommended)\n\n```bash\n# Save credentials once (encrypted with AGENT_BROWSER_ENCRYPTION_KEY)\n# Recommended: pipe password via stdin to avoid shell history exposure\necho \"pass\" | agent-browser auth save github --url https://github.com/login --username user --password-stdin\n\n# Login using saved profile (LLM never sees password)\nagent-browser auth login github\n\n# List/show/delete profiles\nagent-browser auth list\nagent-browser auth show github\nagent-browser auth delete github\n```\n\n### Authentication with State Persistence\n\n```bash\n# Login once and save state\nagent-browser open https://app.example.com/login\nagent-browser snapshot -i\nagent-browser fill @e1 \"$USERNAME\"\nagent-browser fill @e2 \"$PASSWORD\"\nagent-browser click @e3\nagent-browser wait --url \"**/dashboard\"\nagent-browser state save auth.json\n\n# Reuse in future sessions\nagent-browser state load auth.json\nagent-browser open https://app.example.com/dashboard\n```\n\n### Session Persistence\n\n```bash\n# Auto-save/restore cookies and localStorage across browser restarts\nagent-browser --session-name myapp open https://app.example.com/login\n# ... login flow ...\nagent-browser close  # State auto-saved to ~/.agent-browser/sessions/\n\n# Next time, state is auto-loaded\nagent-browser --session-name myapp open https://app.example.com/dashboard\n\n# Encrypt state at rest\nexport AGENT_BROWSER_ENCRYPTION_KEY=$(openssl rand -hex 32)\nagent-browser --session-name secure open https://app.example.com\n\n# Manage saved states\nagent-browser state list\nagent-browser state show myapp-default.json\nagent-browser state clear myapp\nagent-browser state clean --older-than 7\n```\n\n### Data Extraction\n\n```bash\nagent-browser open https://example.com/products\nagent-browser snapshot -i\nagent-browser get text @e5           # Get specific element text\nagent-browser get text body > page.txt  # Get all page text\n\n# JSON output for parsing\nagent-browser snapshot -i --json\nagent-browser get text @e1 --json\n```\n\n### Parallel Sessions\n\n```bash\nagent-browser --session site1 open https://site-a.com\nagent-browser --session site2 open https://site-b.com\n\nagent-browser --session site1 snapshot -i\nagent-browser --session site2 snapshot -i\n\nagent-browser session list\n```\n\n### Connect to Existing Chrome\n\n```bash\n# Auto-discover running Chrome with remote debugging enabled\nagent-browser --auto-connect open https://example.com\nagent-browser --auto-connect snapshot\n\n# Or with explicit CDP port\nagent-browser --cdp 9222 snapshot\n```\n\n### Color Scheme (Dark Mode)\n\n```bash\n# Persistent dark mode via flag (applies to all pages and new tabs)\nagent-browser --color-scheme dark open https://example.com\n\n# Or via environment variable\nAGENT_BROWSER_COLOR_SCHEME=dark agent-browser open https://example.com\n\n# Or set during session (persists for subsequent commands)\nagent-browser set media dark\n```\n\n### Visual Browser (Debugging)\n\n```bash\nagent-browser --headed open https://example.com\nagent-browser highlight @e1          # Highlight element\nagent-browser record start demo.webm # Record session\nagent-browser profiler start         # Start Chrome DevTools profiling\nagent-browser profiler stop trace.json # Stop and save profile (path optional)\n```\n\nUse `AGENT_BROWSER_HEADED=1` to enable headed mode via environment variable. Browser extensions work in both headed and headless mode.\n\n### Local Files (PDFs, HTML)\n\n```bash\n# Open local files with file:// URLs\nagent-browser --allow-file-access open file:///path/to/document.pdf\nagent-browser --allow-file-access open file:///path/to/page.html\nagent-browser screenshot output.png\n```\n\n### iOS Simulator (Mobile Safari)\n\n```bash\n# List available iOS simulators\nagent-browser device list\n\n# Launch Safari on a specific device\nagent-browser -p ios --device \"iPhone 16 Pro\" open https://example.com\n\n# Same workflow as desktop - snapshot, interact, re-snapshot\nagent-browser -p ios snapshot -i\nagent-browser -p ios tap @e1          # Tap (alias for click)\nagent-browser -p ios fill @e2 \"text\"\nagent-browser -p ios swipe up         # Mobile-specific gesture\n\n# Take screenshot\nagent-browser -p ios screenshot mobile.png\n\n# Close session (shuts down simulator)\nagent-browser -p ios close\n```\n\n**Requirements:** macOS with Xcode, Appium (`npm install -g appium && appium driver install xcuitest`)\n\n**Real devices:** Works with physical iOS devices if pre-configured. Use `--device \"<UDID>\"` where UDID is from `xcrun xctrace list devices`.\n\n## Security\n\nAll security features are opt-in. By default, agent-browser imposes no restrictions on navigation, actions, or output.\n\n### Content Boundaries (Recommended for AI Agents)\n\nEnable `--content-boundaries` to wrap page-sourced output in markers that help LLMs distinguish tool output from untrusted page content:\n\n```bash\nexport AGENT_BROWSER_CONTENT_BOUNDARIES=1\nagent-browser snapshot\n# Output:\n# --- AGENT_BROWSER_PAGE_CONTENT nonce=<hex> origin=https://example.com ---\n# [accessibility tree]\n# --- END_AGENT_BROWSER_PAGE_CONTENT nonce=<hex> ---\n```\n\n### Domain Allowlist\n\nRestrict navigation to trusted domains. Wildcards like `*.example.com` also match the bare domain `example.com`. Sub-resource requests, WebSocket, and EventSource connections to non-allowed domains are also blocked. Include CDN domains your target pages depend on:\n\n```bash\nexport AGENT_BROWSER_ALLOWED_DOMAINS=\"example.com,*.example.com\"\nagent-browser open https://example.com        # OK\nagent-browser open https://malicious.com       # Blocked\n```\n\n### Action Policy\n\nUse a policy file to gate destructive actions:\n\n```bash\nexport AGENT_BROWSER_ACTION_POLICY=./policy.json\n```\n\nExample `policy.json`:\n```json\n{\"default\": \"deny\", \"allow\": [\"navigate\", \"snapshot\", \"click\", \"scroll\", \"wait\", \"get\"]}\n```\n\nAuth vault operations (`auth login`, etc.) bypass action policy but domain allowlist still applies.\n\n### Output Limits\n\nPrevent context flooding from large pages:\n\n```bash\nexport AGENT_BROWSER_MAX_OUTPUT=50000\n```\n\n## Diffing (Verifying Changes)\n\nUse `diff snapshot` after performing an action to verify it had the intended effect. This compares the current accessibility tree against the last snapshot taken in the session.\n\n```bash\n# Typical workflow: snapshot -> action -> diff\nagent-browser snapshot -i          # Take baseline snapshot\nagent-browser click @e2            # Perform action\nagent-browser diff snapshot        # See what changed (auto-compares to last snapshot)\n```\n\nFor visual regression testing or monitoring:\n\n```bash\n# Save a baseline screenshot, then compare later\nagent-browser screenshot baseline.png\n# ... time passes or changes are made ...\nagent-browser diff screenshot --baseline baseline.png\n\n# Compare staging vs production\nagent-browser diff url https://staging.example.com https://prod.example.com --screenshot\n```\n\n`diff snapshot` output uses `+` for additions and `-` for removals, similar to git diff. `diff screenshot` produces a diff image with changed pixels highlighted in red, plus a mismatch percentage.\n\n## Timeouts and Slow Pages\n\nThe default Playwright timeout is 25 seconds for local browsers. This can be overridden with the `AGENT_BROWSER_DEFAULT_TIMEOUT` environment variable (value in milliseconds). For slow websites or large pages, use explicit waits instead of relying on the default timeout:\n\n```bash\n# Wait for network activity to settle (best for slow pages)\nagent-browser wait --load networkidle\n\n# Wait for a specific element to appear\nagent-browser wait \"#content\"\nagent-browser wait @e1\n\n# Wait for a specific URL pattern (useful after redirects)\nagent-browser wait --url \"**/dashboard\"\n\n# Wait for a JavaScript condition\nagent-browser wait --fn \"document.readyState === 'complete'\"\n\n# Wait a fixed duration (milliseconds) as a last resort\nagent-browser wait 5000\n```\n\nWhen dealing with consistently slow websites, use `wait --load networkidle` after `open` to ensure the page is fully loaded before taking a snapshot. If a specific element is slow to render, wait for it directly with `wait <selector>` or `wait @ref`.\n\n## Session Management and Cleanup\n\nWhen running multiple agents or automations concurrently, always use named sessions to avoid conflicts:\n\n```bash\n# Each agent gets its own isolated session\nagent-browser --session agent1 open site-a.com\nagent-browser --session agent2 open site-b.com\n\n# Check active sessions\nagent-browser session list\n```\n\nAlways close your browser session when done to avoid leaked processes:\n\n```bash\nagent-browser close                    # Close default session\nagent-browser --session agent1 close   # Close specific session\n```\n\nIf a previous session was not closed properly, the daemon may still be running. Use `agent-browser close` to clean it up before starting new work.\n\n## Ref Lifecycle (Important)\n\nRefs (`@e1`, `@e2`, etc.) are invalidated when the page changes. Always re-snapshot after:\n\n- Clicking links or buttons that navigate\n- Form submissions\n- Dynamic content loading (dropdowns, modals)\n\n```bash\nagent-browser click @e5              # Navigates to new page\nagent-browser snapshot -i            # MUST re-snapshot\nagent-browser click @e1              # Use new refs\n```\n\n## Annotated Screenshots (Vision Mode)\n\nUse `--annotate` to take a screenshot with numbered labels overlaid on interactive elements. Each label `[N]` maps to ref `@eN`. This also caches refs, so you can interact with elements immediately without a separate snapshot.\n\n```bash\nagent-browser screenshot --annotate\n# Output includes the image path and a legend:\n#   [1] @e1 button \"Submit\"\n#   [2] @e2 link \"Home\"\n#   [3] @e3 textbox \"Email\"\nagent-browser click @e2              # Click using ref from annotated screenshot\n```\n\nUse annotated screenshots when:\n- The page has unlabeled icon buttons or visual-only elements\n- You need to verify visual layout or styling\n- Canvas or chart elements are present (invisible to text snapshots)\n- You need spatial reasoning about element positions\n\n## Semantic Locators (Alternative to Refs)\n\nWhen refs are unavailable or unreliable, use semantic locators:\n\n```bash\nagent-browser find text \"Sign In\" click\nagent-browser find label \"Email\" fill \"user@test.com\"\nagent-browser find role button click --name \"Submit\"\nagent-browser find placeholder \"Search\" type \"query\"\nagent-browser find testid \"submit-btn\" click\n```\n\n## JavaScript Evaluation (eval)\n\nUse `eval` to run JavaScript in the browser context. **Shell quoting can corrupt complex expressions** -- use `--stdin` or `-b` to avoid issues.\n\n```bash\n# Simple expressions work with regular quoting\nagent-browser eval 'document.title'\nagent-browser eval 'document.querySelectorAll(\"img\").length'\n\n# Complex JS: use --stdin with heredoc (RECOMMENDED)\nagent-browser eval --stdin <<'EVALEOF'\nJSON.stringify(\n  Array.from(document.querySelectorAll(\"img\"))\n    .filter(i => !i.alt)\n    .map(i => ({ src: i.src.split(\"/\").pop(), width: i.width }))\n)\nEVALEOF\n\n# Alternative: base64 encoding (avoids all shell escaping issues)\nagent-browser eval -b \"$(echo -n 'Array.from(document.querySelectorAll(\"a\")).map(a => a.href)' | base64)\"\n```\n\n**Why this matters:** When the shell processes your command, inner double quotes, `!` characters (history expansion), backticks, and `$()` can all corrupt the JavaScript before it reaches agent-browser. The `--stdin` and `-b` flags bypass shell interpretation entirely.\n\n**Rules of thumb:**\n- Single-line, no nested quotes -> regular `eval 'expression'` with single quotes is fine\n- Nested quotes, arrow functions, template literals, or multiline -> use `eval --stdin <<'EVALEOF'`\n- Programmatic/generated scripts -> use `eval -b` with base64\n\n## Configuration File\n\nCreate `agent-browser.json` in the project root for persistent settings:\n\n```json\n{\n  \"headed\": true,\n  \"proxy\": \"http://localhost:8080\",\n  \"profile\": \"./browser-data\"\n}\n```\n\nPriority (lowest to highest): `~/.agent-browser/config.json` < `./agent-browser.json` < env vars < CLI flags. Use `--config <path>` or `AGENT_BROWSER_CONFIG` env var for a custom config file (exits with error if missing/invalid). All CLI options map to camelCase keys (e.g., `--executable-path` -> `\"executablePath\"`). Boolean flags accept `true`/`false` values (e.g., `--headed false` overrides config). Extensions from user and project configs are merged, not replaced.\n\n## Deep-Dive Documentation\n\n| Reference | When to Use |\n|-----------|-------------|\n| [references/commands.md](references/commands.md) | Full command reference with all options |\n| [references/snapshot-refs.md](references/snapshot-refs.md) | Ref lifecycle, invalidation rules, troubleshooting |\n| [references/session-management.md](references/session-management.md) | Parallel sessions, state persistence, concurrent scraping |\n| [references/authentication.md](references/authentication.md) | Login flows, OAuth, 2FA handling, state reuse |\n| [references/video-recording.md](references/video-recording.md) | Recording workflows for debugging and documentation |\n| [references/profiling.md](references/profiling.md) | Chrome DevTools profiling for performance analysis |\n| [references/proxy-support.md](references/proxy-support.md) | Proxy configuration, geo-testing, rotating proxies |\n\n## Experimental: Native Mode\n\nagent-browser has an experimental native Rust daemon that communicates with Chrome directly via CDP, bypassing Node.js and Playwright entirely. It is opt-in and not recommended for production use yet.\n\n```bash\n# Enable via flag\nagent-browser --native open example.com\n\n# Enable via environment variable (avoids passing --native every time)\nexport AGENT_BROWSER_NATIVE=1\nagent-browser open example.com\n```\n\nThe native daemon supports Chromium and Safari (via WebDriver). Firefox and WebKit are not yet supported. All core commands (navigate, snapshot, click, fill, screenshot, cookies, storage, tabs, eval, etc.) work identically in native mode. Use `agent-browser close` before switching between native and default mode within the same session.\n\n## Ready-to-Use Templates\n\n| Template | Description |\n|----------|-------------|\n| [templates/form-automation.sh](templates/form-automation.sh) | Form filling with validation |\n| [templates/authenticated-session.sh](templates/authenticated-session.sh) | Login once, reuse state |\n| [templates/capture-workflow.sh](templates/capture-workflow.sh) | Content extraction with screenshots |\n\n```bash\n./templates/form-automation.sh https://example.com/form\n./templates/authenticated-session.sh https://app.example.com/login\n./templates/capture-workflow.sh https://example.com ./output\n```\n\n<!-- File: src/resources/skills/api-design/SKILL.md (Tokens: ~2086 | Category: anthropic-skill) -->\n---\nname: api-design\ndescription: Design or review an HTTP/REST/GraphQL API for versioning, pagination, error shapes, idempotency, auth, and evolvability. Use when asked to \"design an API\", \"shape the endpoints\", \"design the schema\", \"add a new endpoint\", \"review this API\", or when building/modifying a public or internal HTTP surface. Complements `design-an-interface` (which is interface-agnostic) by covering HTTP-specific concerns like status codes, cache headers, and breaking-change management.\n---\n\n<objective>\nShape an HTTP or GraphQL API so callers get predictable, evolvable, and honest semantics. The deliverable is a concrete endpoint/schema sketch with: URL or operation names, method/verb, request shape, response shape, error shape, auth model, pagination strategy, and versioning stance. Optimize for \"clients that exist in 2 years\" over \"client that's easy to write today\".\n</objective>\n\n<context>\nGSD-2 has `design-an-interface` for general module-interface design; this skill is the HTTP/GraphQL specialization. REST and GraphQL carry baggage — status codes, verbs, nullability, pagination — that a generic interface-design discussion glosses over.\n\nInvocation points:\n- Adding a new public API endpoint\n- Redesigning an internal API boundary between services\n- Code review of a PR that introduces HTTP handlers\n- A slice whose acceptance criteria include \"the API works\"\n- A GraphQL schema change\n</context>\n\n<core_principle>\n**CALLERS OUTLIVE YOUR ASSUMPTIONS.** An API you ship today has to keep working when your internals change, when the mobile app version two is still in use, and when a third party integrates against it. Design for extension, not just for the current caller.\n\n**HONEST STATUS CODES.** 200 OK with `{\"error\": \"not found\"}` is a lie. 404 says not found. Use the HTTP semantics the protocol offers — HTTP clients, caches, and intermediaries rely on them.\n\n**PAGINATION IS NON-OPTIONAL.** Any list endpoint that doesn't paginate will eventually get a request for \"all records\" that kills your database.\n</core_principle>\n\n<process>\n\n## Step 1: Gather the contract\n\nAnswer, or ask (one round, 1–3 questions):\n\n1. **Who are the callers?** Internal service / mobile app / public third-party / same-repo frontend.\n2. **What's the versioning stance?** None / URL-path (`/v1/`) / header-based / GraphQL schema evolution.\n3. **Auth model?** Public / API key / OAuth / session cookie / mTLS / none-but-internal-only.\n4. **Idempotency expectation?** Is a retry safe? Required?\n5. **Consistency model?** Read-your-writes, eventual, serializable?\n\n## Step 2: Resource and operation naming\n\n### REST\n\n- Nouns not verbs in URLs: `POST /users`, not `POST /createUser`.\n- Plural resources: `/users/42`, not `/user/42`.\n- Nested only when the relationship is hierarchical and the child has no independent identity: `/users/42/sessions/3`. Otherwise flat: `/sessions/3?userId=42`.\n- Use subresources for actions that don't fit CRUD: `POST /users/42:deactivate` (colon syntax) or `POST /users/42/actions/deactivate`.\n\n### GraphQL\n\n- Queries are nouns; mutations are verbs: `user(id)`, `createUser(input)`, `deactivateUser(id)`.\n- Group related mutations under an input type: `createUser(input: CreateUserInput!)`.\n- Return the affected object plus any derived/computed fields from mutations — lets clients avoid a refetch.\n\n## Step 3: Methods and status codes\n\n### REST\n\n| Method | Intent | Idempotent? | Default success |\n|---|---|---|---|\n| GET | Read | Yes | 200, or 304 if conditional |\n| POST | Create or non-idempotent action | No | 201 with `Location` on create, 200 on action |\n| PUT | Replace (full-object) | Yes | 200 with body, or 204 |\n| PATCH | Partial update | No (usually) | 200 with body |\n| DELETE | Remove | Yes | 204 |\n\nErrors:\n- 400: caller screwed up the request shape\n- 401: no/invalid auth\n- 403: authed but not allowed\n- 404: resource doesn't exist\n- 409: conflict (version mismatch, unique constraint)\n- 410: gone (vs 404 when the resource previously existed and you want to signal that)\n- 422: validation failed\n- 429: rate-limited — include `Retry-After`\n- 500: genuinely unexpected server error\n- 503: service down or overloaded — include `Retry-After`\n\nNever 200-with-error-body. Never 500 for a 4xx cause.\n\n### GraphQL\n\n- Top-level errors (`errors[]`) for transport-level failures. Domain errors (validation, not-found, forbidden) go in the typed return — use a union or result type.\n- Partial results are expected; design the schema so `null` on a field is meaningful, not a signal of generic failure.\n\n## Step 4: Pagination\n\n- **Cursor-based by default.** Opaque cursor string, `limit`, return `nextCursor` when more exists. Scales, stable under writes.\n- **Offset-based only when:** dataset is small, user needs jump-to-page semantics (admin tables), and you're willing to accept stability drift.\n- **Never \"return everything\"** as default. Put a hard upper bound on `limit` (e.g., 200).\n- GraphQL: use Relay-style connections (`edges`, `pageInfo`) if the ecosystem expects it; otherwise a simpler `{items, nextCursor}` is fine.\n\n## Step 5: Error shape\n\nStandardize one shape and use it everywhere. Example REST:\n\n```json\n{\n  \"error\": {\n    \"code\": \"user_not_found\",\n    \"message\": \"No user with id 42\",\n    \"details\": { \"userId\": 42 },\n    \"requestId\": \"req_abc123\"\n  }\n}\n```\n\n- `code` is machine-readable; stable; documented.\n- `message` is human-readable; can change.\n- `details` carries structured context.\n- `requestId` lets callers report bugs.\n\nErrors don't leak stack traces, file paths, or internal queries.\n\n## Step 6: Idempotency, caching, concurrency\n\n- **Idempotency keys** for POST operations that mustn't double-execute on retry. Caller passes `Idempotency-Key: <uuid>`; server dedupes for a window.\n- **ETags** for GET + conditional updates (`If-Match` on PUT/PATCH).\n- **Cache-Control** on GETs that are safely cacheable.\n- **Optimistic concurrency:** when multiple writers collide, 409 with the current state. Don't silently clobber.\n\n## Step 7: Versioning and evolution\n\n- **Additive changes are free:** new optional fields, new endpoints, new optional query params.\n- **Breaking changes need a plan:** path-versioned (`/v2/`), sunset headers on `/v1/`, deprecation window communicated. Or, for GraphQL, `@deprecated` on fields with a migration note.\n- **Document the contract:** OpenAPI/GraphQL SDL. Keep it in the repo. Make it part of the PR that introduces the change.\n\n## Step 8: Review or write it up\n\nIf this is a review, produce findings in the same shape as `security-review` / `review` — file:line, category, recommendation.\n\nIf this is a new design, produce:\n\n```markdown\n## <API name>\n\n### Scope\n<what the API is for, who calls it>\n\n### Endpoints / Operations\n- `POST /users` — create user. Request: `{email, name}`. Response 201: `{id, email, name, createdAt}` + `Location: /users/<id>`. Errors: 409 email taken, 422 invalid.\n- ...\n\n### Auth\n<model + where to put the credential>\n\n### Pagination\n<cursor shape, max limit>\n\n### Error shape\n<one canonical shape>\n\n### Idempotency / concurrency\n<rules>\n\n### Versioning\n<stance + how breaking changes will be handled>\n\n### OpenAPI / SDL\n<link or inline>\n```\n\nAppend architectural decisions to `.gsd/DECISIONS.md`.\n\n</process>\n\n<anti_patterns>\n\n- **200 OK with `{\"error\": \"...\"}`.** Lies to caches, proxies, retry libraries.\n- **Unbounded list endpoints.** `GET /users` without a `limit` cap will bite you.\n- **Offset pagination at scale.** Drifts under writes; slow at high offsets.\n- **Free-form error messages with no code.** Machine callers can't branch on prose.\n- **Breaking changes in-place.** Callers break; versioning exists for a reason.\n- **Ignoring idempotency on retriable POSTs.** Double-charges, duplicate records.\n- **Auth checks at the handler only, not the service layer.** Defense in depth.\n\n</anti_patterns>\n\n<success_criteria>\n\n- [ ] Every endpoint/operation has named request, response, and error shapes.\n- [ ] Status codes match HTTP semantics — no 200-with-error.\n- [ ] List endpoints paginate; max limit is documented.\n- [ ] A single error shape is used everywhere, with a machine-readable code.\n- [ ] Versioning stance is stated — even if the answer is \"additive only for now.\"\n- [ ] OpenAPI/SDL reflects the design and lives in the repo.\n- [ ] Decisions appear in `.gsd/DECISIONS.md`.\n\n</success_criteria>\n\n<!-- File: src/resources/skills/best-practices/SKILL.md (Tokens: ~2955 | Category: anthropic-skill) -->\n---\nname: best-practices\ndescription: Apply modern web development best practices for security, compatibility, and code quality. Use when asked to \"apply best practices\", \"security audit\", \"modernize code\", \"code quality review\", or \"check for vulnerabilities\".\nlicense: MIT\nmetadata:\n  author: web-quality-skills\n  version: \"1.0\"\n---\n\n# Best practices\n\nModern web development standards based on Lighthouse best practices audits. Covers security, browser compatibility, and code quality patterns.\n\n## Security\n\n### HTTPS everywhere\n\n**Enforce HTTPS:**\n```html\n<!-- ❌ Mixed content -->\n<img src=\"http://example.com/image.jpg\">\n<script src=\"http://cdn.example.com/script.js\"></script>\n\n<!-- ✅ HTTPS only -->\n<img src=\"https://example.com/image.jpg\">\n<script src=\"https://cdn.example.com/script.js\"></script>\n\n<!-- ✅ Protocol-relative (will use page's protocol) -->\n<img src=\"//example.com/image.jpg\">\n```\n\n**HSTS Header:**\n```\nStrict-Transport-Security: max-age=31536000; includeSubDomains; preload\n```\n\n### Content Security Policy (CSP)\n\n```html\n<!-- Basic CSP via meta tag -->\n<meta http-equiv=\"Content-Security-Policy\" \n      content=\"default-src 'self'; \n               script-src 'self' https://trusted-cdn.com; \n               style-src 'self' 'unsafe-inline';\n               img-src 'self' data: https:;\n               connect-src 'self' https://api.example.com;\">\n\n<!-- Better: HTTP header -->\n```\n\n**CSP Header (recommended):**\n```\nContent-Security-Policy: \n  default-src 'self';\n  script-src 'self' 'nonce-abc123' https://trusted.com;\n  style-src 'self' 'nonce-abc123';\n  img-src 'self' data: https:;\n  connect-src 'self' https://api.example.com;\n  frame-ancestors 'self';\n  base-uri 'self';\n  form-action 'self';\n```\n\n**Using nonces for inline scripts:**\n```html\n<script nonce=\"abc123\">\n  // This inline script is allowed\n</script>\n```\n\n### Security headers\n\n```\n# Prevent clickjacking\nX-Frame-Options: DENY\n\n# Prevent MIME type sniffing\nX-Content-Type-Options: nosniff\n\n# Enable XSS filter (legacy browsers)\nX-XSS-Protection: 1; mode=block\n\n# Control referrer information\nReferrer-Policy: strict-origin-when-cross-origin\n\n# Permissions policy (formerly Feature-Policy)\nPermissions-Policy: geolocation=(), microphone=(), camera=()\n```\n\n### No vulnerable libraries\n\n```bash\n# Check for vulnerabilities\nnpm audit\nyarn audit\n\n# Auto-fix when possible\nnpm audit fix\n\n# Check specific package\nnpm ls lodash\n```\n\n**Keep dependencies updated:**\n```json\n// package.json\n{\n  \"scripts\": {\n    \"audit\": \"npm audit --audit-level=moderate\",\n    \"update\": \"npm update && npm audit fix\"\n  }\n}\n```\n\n**Known vulnerable patterns to avoid:**\n```javascript\n// ❌ Prototype pollution vulnerable patterns\nObject.assign(target, userInput);\n_.merge(target, userInput);\n\n// ✅ Safer alternatives\nconst safeData = JSON.parse(JSON.stringify(userInput));\n```\n\n### Input sanitization\n\n```javascript\n// ❌ XSS vulnerable\nelement.innerHTML = userInput;\ndocument.write(userInput);\n\n// ✅ Safe text content\nelement.textContent = userInput;\n\n// ✅ If HTML needed, sanitize\nimport DOMPurify from 'dompurify';\nelement.innerHTML = DOMPurify.sanitize(userInput);\n```\n\n### Secure cookies\n\n```javascript\n// ❌ Insecure cookie\ndocument.cookie = \"session=abc123\";\n\n// ✅ Secure cookie (server-side)\nSet-Cookie: session=abc123; Secure; HttpOnly; SameSite=Strict; Path=/\n```\n\n---\n\n## Browser compatibility\n\n### Doctype declaration\n\n```html\n<!-- ❌ Missing or invalid doctype -->\n<HTML>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n\n<!-- ✅ HTML5 doctype -->\n<!DOCTYPE html>\n<html lang=\"en\">\n```\n\n### Character encoding\n\n```html\n<!-- ❌ Missing or late charset -->\n<html>\n<head>\n  <title>Page</title>\n  <meta charset=\"UTF-8\">\n</head>\n\n<!-- ✅ Charset as first element in head -->\n<html>\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Page</title>\n</head>\n```\n\n### Viewport meta tag\n\n```html\n<!-- ❌ Missing viewport -->\n<head>\n  <title>Page</title>\n</head>\n\n<!-- ✅ Responsive viewport -->\n<head>\n  <meta charset=\"UTF-8\">\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n  <title>Page</title>\n</head>\n```\n\n### Feature detection\n\n```javascript\n// ❌ Browser detection (brittle)\nif (navigator.userAgent.includes('Chrome')) {\n  // Chrome-specific code\n}\n\n// ✅ Feature detection\nif ('IntersectionObserver' in window) {\n  // Use IntersectionObserver\n} else {\n  // Fallback\n}\n\n// ✅ Using @supports in CSS\n@supports (display: grid) {\n  .container {\n    display: grid;\n  }\n}\n\n@supports not (display: grid) {\n  .container {\n    display: flex;\n  }\n}\n```\n\n### Polyfills (when needed)\n\n```html\n<!-- Load polyfills conditionally -->\n<script>\n  if (!('fetch' in window)) {\n    document.write('<script src=\"/polyfills/fetch.js\"><\\/script>');\n  }\n</script>\n\n<!-- Or use polyfill.io -->\n<script src=\"https://polyfill.io/v3/polyfill.min.js?features=fetch,IntersectionObserver\"></script>\n```\n\n---\n\n## Deprecated APIs\n\n### Avoid these\n\n```javascript\n// ❌ document.write (blocks parsing)\ndocument.write('<script src=\"...\"></script>');\n\n// ✅ Dynamic script loading\nconst script = document.createElement('script');\nscript.src = '...';\ndocument.head.appendChild(script);\n\n// ❌ Synchronous XHR (blocks main thread)\nconst xhr = new XMLHttpRequest();\nxhr.open('GET', url, false); // false = synchronous\n\n// ✅ Async fetch\nconst response = await fetch(url);\n\n// ❌ Application Cache (deprecated)\n<html manifest=\"cache.manifest\">\n\n// ✅ Service Workers\nif ('serviceWorker' in navigator) {\n  navigator.serviceWorker.register('/sw.js');\n}\n```\n\n### Event listener passive\n\n```javascript\n// ❌ Non-passive touch/wheel (may block scrolling)\nelement.addEventListener('touchstart', handler);\nelement.addEventListener('wheel', handler);\n\n// ✅ Passive listeners (allows smooth scrolling)\nelement.addEventListener('touchstart', handler, { passive: true });\nelement.addEventListener('wheel', handler, { passive: true });\n\n// ✅ If you need preventDefault, be explicit\nelement.addEventListener('touchstart', handler, { passive: false });\n```\n\n---\n\n## Console & errors\n\n### No console errors\n\n```javascript\n// ❌ Errors in production\nconsole.log('Debug info'); // Remove in production\nthrow new Error('Unhandled'); // Catch all errors\n\n// ✅ Proper error handling\ntry {\n  riskyOperation();\n} catch (error) {\n  // Log to error tracking service\n  errorTracker.captureException(error);\n  // Show user-friendly message\n  showErrorMessage('Something went wrong. Please try again.');\n}\n```\n\n### Error boundaries (React)\n\n```jsx\nclass ErrorBoundary extends React.Component {\n  state = { hasError: false };\n  \n  static getDerivedStateFromError(error) {\n    return { hasError: true };\n  }\n  \n  componentDidCatch(error, info) {\n    errorTracker.captureException(error, { extra: info });\n  }\n  \n  render() {\n    if (this.state.hasError) {\n      return <FallbackUI />;\n    }\n    return this.props.children;\n  }\n}\n\n// Usage\n<ErrorBoundary>\n  <App />\n</ErrorBoundary>\n```\n\n### Global error handler\n\n```javascript\n// Catch unhandled errors\nwindow.addEventListener('error', (event) => {\n  errorTracker.captureException(event.error);\n});\n\n// Catch unhandled promise rejections\nwindow.addEventListener('unhandledrejection', (event) => {\n  errorTracker.captureException(event.reason);\n});\n```\n\n---\n\n## Source maps\n\n### Production configuration\n\n```javascript\n// ❌ Source maps exposed in production\n// webpack.config.js\nmodule.exports = {\n  devtool: 'source-map', // Exposes source code\n};\n\n// ✅ Hidden source maps (uploaded to error tracker)\nmodule.exports = {\n  devtool: 'hidden-source-map',\n};\n\n// ✅ Or no source maps in production\nmodule.exports = {\n  devtool: process.env.NODE_ENV === 'production' ? false : 'source-map',\n};\n```\n\n---\n\n## Performance best practices\n\n### Avoid blocking patterns\n\n```javascript\n// ❌ Blocking script\n<script src=\"heavy-library.js\"></script>\n\n// ✅ Deferred script\n<script defer src=\"heavy-library.js\"></script>\n\n// ❌ Blocking CSS import\n@import url('other-styles.css');\n\n// ✅ Link tags (parallel loading)\n<link rel=\"stylesheet\" href=\"styles.css\">\n<link rel=\"stylesheet\" href=\"other-styles.css\">\n```\n\n### Efficient event handlers\n\n```javascript\n// ❌ Handler on every element\nitems.forEach(item => {\n  item.addEventListener('click', handleClick);\n});\n\n// ✅ Event delegation\ncontainer.addEventListener('click', (e) => {\n  if (e.target.matches('.item')) {\n    handleClick(e);\n  }\n});\n```\n\n### Memory management\n\n```javascript\n// ❌ Memory leak (never removed)\nconst handler = () => { /* ... */ };\nwindow.addEventListener('resize', handler);\n\n// ✅ Cleanup when done\nconst handler = () => { /* ... */ };\nwindow.addEventListener('resize', handler);\n\n// Later, when component unmounts:\nwindow.removeEventListener('resize', handler);\n\n// ✅ Using AbortController\nconst controller = new AbortController();\nwindow.addEventListener('resize', handler, { signal: controller.signal });\n\n// Cleanup:\ncontroller.abort();\n```\n\n---\n\n## Code quality\n\n### Valid HTML\n\n```html\n<!-- ❌ Invalid HTML -->\n<div id=\"header\">\n<div id=\"header\"> <!-- Duplicate ID -->\n\n<ul>\n  <div>Item</div> <!-- Invalid child -->\n</ul>\n\n<a href=\"/\"><button>Click</button></a> <!-- Invalid nesting -->\n\n<!-- ✅ Valid HTML -->\n<header id=\"site-header\">\n</header>\n\n<ul>\n  <li>Item</li>\n</ul>\n\n<a href=\"/\" class=\"button\">Click</a>\n```\n\n### Semantic HTML\n\n```html\n<!-- ❌ Non-semantic -->\n<div class=\"header\">\n  <div class=\"nav\">\n    <div class=\"nav-item\">Home</div>\n  </div>\n</div>\n<div class=\"main\">\n  <div class=\"article\">\n    <div class=\"title\">Headline</div>\n  </div>\n</div>\n\n<!-- ✅ Semantic HTML5 -->\n<header>\n  <nav>\n    <a href=\"/\">Home</a>\n  </nav>\n</header>\n<main>\n  <article>\n    <h1>Headline</h1>\n  </article>\n</main>\n```\n\n### Image aspect ratios\n\n```html\n<!-- ❌ Distorted images -->\n<img src=\"photo.jpg\" width=\"300\" height=\"100\">\n<!-- If actual ratio is 4:3, this squishes the image -->\n\n<!-- ✅ Preserve aspect ratio -->\n<img src=\"photo.jpg\" width=\"300\" height=\"225\">\n<!-- Actual 4:3 dimensions -->\n\n<!-- ✅ CSS object-fit for flexibility -->\n<img src=\"photo.jpg\" style=\"width: 300px; height: 200px; object-fit: cover;\">\n```\n\n---\n\n## Permissions & privacy\n\n### Request permissions properly\n\n```javascript\n// ❌ Request on page load (bad UX, often denied)\nnavigator.geolocation.getCurrentPosition(success, error);\n\n// ✅ Request in context, after user action\nfindNearbyButton.addEventListener('click', async () => {\n  // Explain why you need it\n  if (await showPermissionExplanation()) {\n    navigator.geolocation.getCurrentPosition(success, error);\n  }\n});\n```\n\n### Permissions policy\n\n```html\n<!-- Restrict powerful features -->\n<meta http-equiv=\"Permissions-Policy\" \n      content=\"geolocation=(), camera=(), microphone=()\">\n\n<!-- Or allow for specific origins -->\n<meta http-equiv=\"Permissions-Policy\" \n      content=\"geolocation=(self 'https://maps.example.com')\">\n```\n\n---\n\n## Audit checklist\n\n### Security (critical)\n- [ ] HTTPS enabled, no mixed content\n- [ ] No vulnerable dependencies (`npm audit`)\n- [ ] CSP headers configured\n- [ ] Security headers present\n- [ ] No exposed source maps\n\n### Compatibility\n- [ ] Valid HTML5 doctype\n- [ ] Charset declared first in head\n- [ ] Viewport meta tag present\n- [ ] No deprecated APIs used\n- [ ] Passive event listeners for scroll/touch\n\n### Code quality\n- [ ] No console errors\n- [ ] Valid HTML (no duplicate IDs)\n- [ ] Semantic HTML elements used\n- [ ] Proper error handling\n- [ ] Memory cleanup in components\n\n### UX\n- [ ] No intrusive interstitials\n- [ ] Permission requests in context\n- [ ] Clear error messages\n- [ ] Appropriate image aspect ratios\n\n## Tools\n\n| Tool | Purpose |\n|------|---------|\n| `npm audit` | Dependency vulnerabilities |\n| [SecurityHeaders.com](https://securityheaders.com) | Header analysis |\n| [W3C Validator](https://validator.w3.org) | HTML validation |\n| Lighthouse | Best practices audit |\n| [Observatory](https://observatory.mozilla.org) | Security scan |\n\n## References\n\n- [MDN Web Security](https://developer.mozilla.org/en-US/docs/Web/Security)\n- [OWASP Top 10](https://owasp.org/www-project-top-ten/)\n- [Web Quality Audit](../web-quality-audit/SKILL.md)\n\n<!-- File: src/resources/skills/btw/SKILL.md (Tokens: ~502 | Category: anthropic-skill) -->\n---\nname: btw\ndescription: Ask a quick side question about your current work without derailing the main task. Answers from existing conversation context only — no tool calls, no file reads, single concise response. Use when you need a fast answer from what is already in this session.\n---\n\n<objective>\nAnswer a quick side question using only what is already present in the current conversation context. Do not read files, run commands, search, or use any tools. Give a single, concise response and return focus to the main work.\n</objective>\n\n<behavior>\n**This is a side question, not a task.**\n\n- Answer only from information already in the conversation (files read, decisions made, code seen, context established)\n- Do NOT use any tools — no Read, no Bash, no Grep, no Search\n- If the answer requires reading something new, say so briefly and suggest the user ask as a normal prompt instead\n- Keep the response short and direct — one to a few sentences unless the question genuinely needs more\n- Do not summarize the main work, ask follow-up questions, or offer to do anything else\n- After answering, stop — do not prompt for next steps\n</behavior>\n\n<quick_start>\nParse the argument after `/btw` as the question. Answer it directly from context.\n\nIf no argument is provided, ask: \"What did you want to know?\"\n\nIf the question cannot be answered from current context (requires reading a file, running a command, or information not yet in the session), respond with:\n\"I'd need to [read X / run Y / look up Z] to answer that — ask it as a normal prompt when you're ready.\"\n</quick_start>\n\n<examples>\n**Good uses of /btw:**\n- `/btw what was the name of that config file again?` → answers from files already read in session\n- `/btw which branch are we on?` → answers from git context already established\n- `/btw did we already handle the null case in that function?` → answers from code already reviewed\n- `/btw what model does this use?` → answers from code or config already in context\n\n**Not a good fit for /btw (suggest normal prompt):**\n- Questions requiring reading a file not yet seen\n- Questions requiring running a command\n- Questions needing a multi-step answer or follow-up\n- Starting a new task or changing direction\n</examples>\n\n<!-- File: src/resources/skills/code-optimizer/references/algorithmic-complexity.md (Tokens: ~749 | Category: anthropic-skill) -->\n# Algorithmic Complexity\n\n## Grep/Glob Patterns to Detect\n\n### O(n^2) and Worse Patterns\n```\n# Nested loops over same/related collections\nfor.*in.*\\n.*for.*in         (nested for loops)\n\\.forEach\\(.*\\.forEach\\(      (nested forEach)\n\\.map\\(.*\\.map\\(              (nested map)\n\\.filter\\(.*\\.includes\\(      (filter+includes = O(n*m))\n\\.find\\(.*inside.*\\.map\\(     (find inside map)\n\\.indexOf\\(.*inside.*for      (indexOf in loop)\n\\.includes\\(.*inside.*for     (includes in loop)\n# Array as lookup table\narray\\.find\\(.*===            (use Map/Set instead)\narray\\.some\\(.*===            (use Set.has instead)\nlist\\.index\\(                 (Python: use dict instead)\nif.*in\\s+list                 (Python: O(n) lookup in list)\n```\n\n### Unnecessary Iterations\n```\n\\.filter\\(.*\\.length          (filter just to count)\n\\.filter\\(.*\\[0\\]             (filter just to get first - use find)\n\\.map\\(.*\\.filter\\(           (map then filter - combine or reverse order)\n\\.filter\\(.*\\.map\\(.*\\.filter (multiple passes when one suffices)\n\\.sort\\(\\).*\\[0\\]             (sort to get min/max - use Math.min/max or reduce)\n\\.sort\\(\\).*\\.slice\\(0        (sort to get top-k - use partial sort/heap)\nsorted\\(.*\\)\\[0\\]             (Python: use min() instead)\nsorted\\(.*\\)\\[-1\\]            (Python: use max() instead)\n\\.reverse\\(\\).*\\.forEach      (reverse just to iterate backwards)\nObject\\.keys\\(.*\\.map\\(.*Object\\.values  (iterating keys then accessing values)\n```\n\n### Redundant Computation\n```\n# Same computation in loop\nfor.*\\n.*Math\\.              (math operations that could be hoisted)\nfor.*\\n.*\\.length            (accessing .length repeatedly - may be fine, check)\nfor.*\\n.*document\\.querySelector  (DOM queries in loops)\nfor.*\\n.*JSON\\.parse         (parsing same JSON repeatedly)\nfor.*\\n.*new RegExp\\(        (creating regex in loop)\nfor.*\\n.*new Date\\(          (creating Date objects in loop for same date)\n```\n\n### Inefficient Data Structure Choice\n```\n# Using arrays where Set/Map would be better\n\\.push\\(.*\\.includes\\(       (array as unique set)\n\\.filter\\(.*\\.indexOf\\(       (dedup with filter+indexOf)\n\\[\\].*\\.find\\(               (array for lookups)\n# Using objects where Map would be better\n\\{\\}.*\\[.*\\]\\s*=             (frequent dynamic key insertion)\ndelete.*\\[                   (frequent key deletion from object)\n```\n\n## Improvement Strategies\n\n1. **Nested loops**: Pre-build lookup Map/Set, use hash-based approaches\n2. **Filter+includes**: Convert one collection to Set for O(1) lookups\n3. **Sort for min/max**: Use Math.min/max, reduce, or heap for top-k\n4. **Multiple passes**: Combine into single reduce/loop\n5. **Redundant computation**: Hoist invariants out of loops, memoize\n6. **Array as lookup**: Use Map for key-value, Set for existence checks\n7. **String matching in loops**: Pre-compile regex, use Map for exact matches\n\n<!-- File: src/resources/skills/code-optimizer/references/build-compilation.md (Tokens: ~805 | Category: anthropic-skill) -->\n# Build & Compilation Optimization\n\n## Grep/Glob Patterns to Detect\n\n### Unoptimized Build Config\n```\n# Webpack\nmode:\\s*['\"]development['\"]        (dev mode in production build)\ndevtool:\\s*['\"]source-map['\"]      (full source maps in production)\ndevtool:\\s*['\"]eval                (eval source maps in production)\n# No code splitting\nsplitChunks.*false                  (code splitting disabled)\n# No minification\nminimize:\\s*false                   (minification disabled)\n# Missing tree shaking\nsideEffects.*true                   (prevents tree shaking)\n```\n\n### Development-Only Code in Production\n```\nconsole\\.log\\(                     (debug logging)\nconsole\\.debug\\(                   (debug logging)\nconsole\\.trace\\(                   (trace logging)\ndebugger;                           (debugger statement)\n\\.only\\(                           (test.only left in)\n\\.skip\\(                           (test.skip left in)\nif\\s*\\(.*process\\.env\\.NODE_ENV.*development  (dev-only code)\n__DEV__                             (React Native dev flag)\n```\n\n### Missing Optimization Flags\n```\n# TypeScript\n\"strict\":\\s*false                  (strict mode disabled)\n\"skipLibCheck\":\\s*false            (slow lib checking)\n\"incremental\":\\s*false             (no incremental compilation)\n# Python\npython\\s+-O                        (check if optimized flag used)\n__debug__                           (debug-only code)\n# Docker\nFROM.*:latest                      (unpinned base image)\nRUN.*pip install(?!.*--no-cache)   (pip without --no-cache-dir)\nRUN.*npm install(?!.*--production) (npm install without --production)\nCOPY\\s+\\.\\s+\\.                     (copying entire context)\n```\n\n### Large/Slow Imports at Startup\n```\n# Top-level heavy imports that could be lazy\nimport.*tensorflow                  (heavy ML library at top)\nimport.*pandas                      (heavy data library at top)\nimport.*matplotlib                  (heavy viz library at top)\nimport.*scipy                       (heavy math library at top)\nfrom.*import\\s+\\*                   (wildcard imports slow startup)\n# Circular imports\nImportError.*circular               (circular import errors)\n```\n\n### Missing Caching in CI/CD\n```\n# No caching steps\nnpm install(?!.*cache)              (npm install without cache)\npip install(?!.*cache)              (pip install without cache)\ngo build(?!.*cache)                 (go build without cache)\ndocker build(?!.*cache)             (docker build without layer cache)\n```\n\n### Slow Test Suite\n```\n# Real I/O in tests\nfetch\\(.*test                       (real network calls in tests)\nrequests\\.\\w+\\(.*test              (real HTTP in Python tests)\nopen\\(.*test                        (real file I/O in tests)\n# No test parallelization\n--runInBand                         (Jest sequential mode)\n-p no:xdist                         (pytest parallelization disabled)\n# Heavy setup/teardown\nbeforeAll.*database                 (real DB setup in tests)\nsetUp.*database                     (real DB in Python tests)\n```\n\n## Improvement Strategies\n\n1. **Build config**: Ensure production mode, minification, tree shaking, code splitting\n2. **Dev code**: Strip console.log/debugger via build plugin (e.g., babel-plugin-transform-remove-console)\n3. **TypeScript**: Enable strict, incremental, skipLibCheck for faster builds\n4. **Docker**: Multi-stage builds, .dockerignore, layer caching, pinned versions\n5. **Lazy imports**: Move heavy imports to function scope where they're needed\n6. **CI caching**: Cache node_modules, pip cache, go build cache, Docker layers\n7. **Test speed**: Mock I/O, run tests in parallel, use in-memory DBs for integration tests\n\n<!-- File: src/resources/skills/code-optimizer/references/bundle-dependencies.md (Tokens: ~740 | Category: anthropic-skill) -->\n# Bundle Size & Dependencies\n\n## Grep/Glob Patterns to Detect\n\n### Heavy Imports\n```\nimport\\s+\\w+\\s+from\\s+['\"]lodash['\"]      (full lodash import vs lodash/specific)\nimport\\s+\\w+\\s+from\\s+['\"]moment['\"]      (moment.js - use date-fns/dayjs)\nimport\\s+\\w+\\s+from\\s+['\"]underscore['\"]  (underscore - mostly native now)\nimport\\s+\\*\\s+as                           (wildcard imports prevent tree-shaking)\nrequire\\(['\"]lodash['\"]\\)                   (CJS lodash import)\nfrom\\s+pandas\\s+import\\s+\\*                (full pandas import)\nimport\\s+tensorflow                         (full TF import)\nimport\\s+boto3                              (full AWS SDK)\n```\n\n### Unused Dependencies\n```\n# Check package.json dependencies vs actual imports\n# Check requirements.txt vs actual imports\n# Check go.mod vs actual imports\nimport.*from.*['\"](\\w+)['\"]   (cross-reference with package.json)\n```\n\n### Duplicate Functionality\n```\n# Multiple date libraries\nmoment.*\\n.*date-fns          (both moment and date-fns)\nmoment.*\\n.*dayjs             (both moment and dayjs)\n# Multiple HTTP clients\naxios.*\\n.*node-fetch         (both axios and fetch)\naxios.*\\n.*got                (both axios and got)\n# Multiple utility libraries\nlodash.*\\n.*underscore        (both lodash and underscore)\n# Multiple state managers\nredux.*\\n.*mobx               (both redux and mobx)\nzustand.*\\n.*jotai            (multiple state libs)\n```\n\n### Dev Dependencies in Production\n```\n# devDependencies imported in src/\nimport.*from.*['\"](@testing|jest|mocha|chai|sinon|cypress|storybook)\n# Debug/test code in production\nconsole\\.log\\(\nconsole\\.debug\\(\ndebugger;\n\\.only\\(         (test.only left in)\n```\n\n### Dynamic Imports Missing\n```\n# Large components imported statically that could be lazy\nimport.*Modal       (modals are great candidates for lazy loading)\nimport.*Chart       (charts are heavy)\nimport.*Editor      (rich editors are heavy)\nimport.*PDF         (PDF libs are heavy)\nimport.*Map         (map components are heavy)\n# Route-level components not lazy loaded\nimport.*Page.*from  (page components should often be lazy)\n```\n\n### Large Assets\n```\n# Check for unoptimized assets\n\\.png['\"]          (check if could be webp/avif)\n\\.jpg['\"]          (check if could be webp/avif)\n\\.gif['\"]          (check if could be video/webp)\n\\.svg['\"].*import  (SVGs imported as modules - check size)\nbase64             (inline base64 assets)\ndata:image         (inline images)\n```\n\n## Improvement Strategies\n\n1. **Lodash**: Use `lodash-es/specific` or native equivalents (Array.find, Object.entries, etc.)\n2. **Moment.js**: Replace with date-fns or dayjs (10x smaller)\n3. **Wildcard imports**: Use named imports for tree-shaking\n4. **Unused deps**: Remove from package.json/requirements.txt\n5. **Dynamic imports**: Use React.lazy/import() for heavy, below-fold components\n6. **Images**: Convert to WebP/AVIF, use responsive srcset, lazy load below-fold\n7. **Duplicate libs**: Consolidate to one library per concern\n\n<!-- File: src/resources/skills/code-optimizer/references/caching-memoization.md (Tokens: ~845 | Category: anthropic-skill) -->\n# Caching & Memoization\n\n## Grep/Glob Patterns to Detect\n\n### Missing Memoization\n```\n# Expensive computations without caching\ndef\\s+\\w+\\(.*\\).*:\\s*\\n.*for.*for      (Python: expensive function without @lru_cache)\nfunction\\s+\\w+\\(.*\\).*\\{.*for.*for     (JS: expensive function without memoization)\n# React missing useMemo/useCallback\nconst\\s+\\w+\\s*=\\s*\\w+\\.filter\\(        (derived data on every render)\nconst\\s+\\w+\\s*=\\s*\\w+\\.map\\(           (derived data on every render)\nconst\\s+\\w+\\s*=\\s*\\w+\\.reduce\\(        (derived data on every render)\nconst\\s+\\w+\\s*=\\s*\\w+\\.sort\\(          (sorting on every render)\n# Same computation called multiple times\n(\\w+)\\(same_args\\).*\\1\\(same_args\\)    (same function, same args, called twice)\n```\n\n### Cache Without Invalidation\n```\ncache\\s*=\\s*\\{\\}                        (cache without TTL or max size)\n_cache\\s*=\\s*\\{\\}                       (module cache without eviction)\nmemo\\s*=\\s*\\{\\}                         (memo without invalidation)\n\\.cache\\s*=\\s*\\{\\}                      (instance cache without cleanup)\nCACHE_TTL.*=.*(?:86400|3600.*24)       (very long TTL - stale data risk)\n```\n\n### Redundant API/DB Calls\n```\n# Same query executed multiple times\n\\.query\\(.*same.*\\.query\\(             (duplicate queries)\nfetch\\(['\"]same_url['\"]\\).*fetch\\(     (duplicate fetches)\n# No SWR/stale-while-revalidate\nuseEffect\\(.*fetch\\(.*\\[\\]            (fetch on every mount without caching)\nuseEffect\\(.*axios\\.\\w+\\(.*\\[\\]       (API call on every mount)\ncomponentDidMount.*fetch               (fetch without caching layer)\n```\n\n### Over-Caching\n```\n# Caching things that change frequently\ncache.*user.*session                   (caching session-specific data)\ncache.*real.?time                      (caching real-time data)\ncache.*current.*time                   (caching time-dependent data)\n# Caching large objects\ncache\\[.*\\]\\s*=\\s*.*large             (large objects in cache)\n```\n\n### Missing HTTP Caching\n```\n# API responses without cache headers\nres\\.json\\(                            (check if Cache-Control is set)\nreturn\\s+Response\\(                    (check if cache headers are set)\nreturn\\s+JsonResponse\\(               (Django: check cache headers)\n# Static assets without long cache\nexpress\\.static\\(                      (check maxAge setting)\nnginx.*location.*static               (check expires/cache-control)\n```\n\n### Computed Properties Recalculated\n```\n# Getters that compute on every access\nget\\s+\\w+\\(\\)\\s*\\{.*return.*\\.filter   (getter computing on each access)\nget\\s+\\w+\\(\\)\\s*\\{.*return.*\\.map      (getter computing on each access)\n@property\\s*\\n\\s*def.*\\n.*for          (Python property computing in loop)\n```\n\n## Improvement Strategies\n\n1. **Memoization**: Use @lru_cache (Python), useMemo/useCallback (React), _.memoize (JS)\n2. **Cache invalidation**: Always set TTL and max size; prefer LRU eviction\n3. **API caching**: Use SWR/React Query for client, Redis/Memcached for server\n4. **HTTP caching**: Set Cache-Control headers, use ETags, stale-while-revalidate\n5. **Computed properties**: Cache results with dirty flag or use memoized selectors (reselect)\n6. **Request deduplication**: Deduplicate identical in-flight requests\n7. **Multi-level cache**: L1 (in-memory) -> L2 (Redis) -> L3 (DB) for read-heavy workloads\n\n<!-- ... +328 more modular skills available via /api/skills/gsd-build/gsd-2?path={path} -->\n</yakaai_skills>"}