diff --git a/second-brain/README.md b/second-brain/README.md new file mode 100644 index 0000000..7876205 --- /dev/null +++ b/second-brain/README.md @@ -0,0 +1,19 @@ +# Stackable Second Brain + +An Obsidian-compatible, repository-local knowledge bank for the Stackable product effort. + +## Start here + +- [[product/brief]] — captured product direction and explicit constraints +- [[product/research-blacksmith]] — competitor baseline and opportunity framing +- [[product/decision-log]] — durable decisions and open questions +- [[wayfinder/stackable-product-map]] — planning map and known frontier +- [[skills/index]] — preserved skill instructions and discovery output +- [[sessions/2026-08-21-discovery]] — this session's running record + +## Conventions + +- Keep decisions concise, dated, and linked to source notes. +- Store raw skill output without edits in `skills/`. +- Keep research claims linked to a source. +- Do not put secrets, tokens, customer data, or credentials in this vault. diff --git a/second-brain/product/brief.md b/second-brain/product/brief.md new file mode 100644 index 0000000..290fafc --- /dev/null +++ b/second-brain/product/brief.md @@ -0,0 +1,29 @@ +# Stackable — Product Brief (captured) + +## Product intent + +Stackable is a CI maintainability platform and CLI for teams using GitHub Actions. It should help teams understand, improve, create, and keep CI/CD healthy rather than operate faster CI runners. The reference competitor is Blacksmith, but Stackable's proposed category is CI maintainability. + +## Requested capabilities (unprioritized) + +- Full-scale CI/CD monitoring and a digital-side dashboard for active pull requests and pull-request state. +- A self-updating pull-request comment/report that refreshes on each relevant commit and/or new comment. +- A polished current-state visualization, selected platform information, and GitHub comment integration. +- AI-assisted CI/CD setup: describe the desired workflow, review an iterative proposal, and produce CI/CD configuration. +- Team/organization-ready operations. +- Web application and CLI for people and agents to manage and run needed work. +- Design priorities: efficiency, speed, stability, maintainability, and a notably good interface. + +## Explicit design constraints + +- Palette: purple, onyx, silver, and black. +- Fonts: Geist and Satoshi. +- ~~Use a realistic keyboard image for dashboard/product visuals; no synthetic SVG keyboard approximation.~~ Withdrawn by the product owner on 2026-08-21; do not include a keyboard image. +- Do not use Lucide. Prefer Iconoir icons. +- Use plain, precise, non-generic user-facing language; review UI copy with an unslop-oriented pass. +- Treat Watermelon as the first source for UI components, layouts, interactions, and animations. The brief also names ReactBits, Aceternity UI, and Shoogle as sources to investigate. Do not hand-roll components before source suitability is verified. +- The request mentions a `Design.md` skill/reference, but no such file exists in the checkout yet. + +## Generated PR-status visualization + +Stackable must generate a functional, deterministic, code-rendered status visualization for use alongside GitHub comments. It should update from API-backed current state, selected CI platform, and related GitHub context. SVG is acceptable as an output format because it is generated from verified state, styled intentionally, and serves operational information; it must never be AI-generated decorative art. diff --git a/second-brain/product/decision-log.md b/second-brain/product/decision-log.md new file mode 100644 index 0000000..771988a --- /dev/null +++ b/second-brain/product/decision-log.md @@ -0,0 +1,43 @@ +# Decision Log + +## Confirmed preferences + +- **2026-08-21 — Product category:** CI maintainability, not CI runner infrastructure. +- **2026-08-21 — Surfaces:** web application plus agent-friendly CLI. +- **2026-08-21 — GitHub integration:** PR state and auto-updating reports are central. +- **2026-08-21 — Visual direction:** purple / onyx / silver / black; Geist + Satoshi; Iconoir rather than Lucide. +- **2026-08-21 — Knowledge management:** keep a repository-local Obsidian-compatible second brain. +- **2026-08-21 — Initial audience:** serve both small GitHub Actions engineering teams and individual developers/coding agents, with shared CI intelligence rather than separate products. +- **2026-08-21 — v1 scope:** the first public version must include PR CI health, AI CI/CD authoring, and organization CI management together; sequence delivery internally as needed, but do not present the first release as a single-pillar tool. +- **2026-08-21 — GitHub boundary:** support GitHub.com in v1; defer GitHub Enterprise Server compatibility. +- **2026-08-21 — AI change authority:** authorized users and agents may directly apply CI/CD changes in v1. +- **2026-08-21 — Direct-write policy:** organization administrators select the branches Stackable may modify directly. The policy must be visible, auditable, and enforceable in both web and CLI flows. +- **2026-08-21 — Identity:** use a GitHub App for organization/repository access, GitHub OAuth for people, and device-flow/scoped API tokens for CLI users and agents. +- **2026-08-21 — CI data boundary:** retain structured CI metadata and bounded failure excerpts by default; link to GitHub for complete logs. Do not ingest full logs by default. +- **2026-08-21 — CI provider scope:** Stackable supports GitHub Actions, CircleCI, and Buildkite from day one, while GitHub.com remains the source-control boundary. +- **2026-08-21 — Dashboard direction:** expose PR command-center work, organization health, and AI workflow creation as three equal top-level workspaces. +- **2026-08-21 — Keyboard visual:** withdrawn; do not include a keyboard image in the product UI. +- **2026-08-21 — Organization authorization:** use four roles—Owner, Admin, Member, and scoped Agent—with policies enforced consistently across web and CLI. +- **2026-08-21 — Agent interface:** ship a CLI/API and a first-class MCP server in v1. +- **2026-08-21 — AI authoring flow:** use a staged Review Canvas—intent, repository-aware interview, plan/assumptions, diff, validation, explicit apply, and audit record. The interview must probe deeply in the same one-question-at-a-time style used for product discovery. +- **2026-08-21 — AI workflow validation:** use provider-aware static validation plus a second, adversarial AI review that checks the proposed change against the user's directive and deliberately hunts for omissions, unsafe assumptions, and likely issues. Do not require a preview run in v1. +- **2026-08-21 — Direct-write rollback:** detect regressions and propose an authorized revert; do not automatically revert or merely observe. +- **2026-08-21 — PR report hierarchy:** show one clear next action first, then the pipeline/state map, then health or risk context. +- **2026-08-21 — PR risk signal:** compute risk from transparent, deterministic, inspectable factors; do not make an AI judgment the primary score. +- **2026-08-21 — Onboarding:** a guided organization setup installs the GitHub App, connects CI providers, selects repositories and writable branches, then supplies CLI/MCP setup. +- **2026-08-21 — CD boundary:** Stackable creates and maintains deployment configuration and monitors deployment state, but does not initiate deployments in v1. +- **2026-08-21 — PR-state visualization:** generate an API-backed, deterministic, code-rendered multi-provider status strip for use beside GitHub comments. SVG is permitted as a functional output format—not as AI-generated decoration. It is a live current-state render because Stackable deletes and replaces its prior canonical comment. +- **2026-08-21 — State ingestion:** use provider webhooks for immediate updates, backed by adaptive polling that reconciles missed or unsupported events. +- **2026-08-21 — PR comment cadence:** debounce bursts of provider events; refresh immediately for terminal failure/recovery or manual refresh, otherwise coalesce updates for roughly 30–60 seconds. +- **2026-08-21 — Dashboard density:** use a balanced product workspace with comfortable spacing and operational detail available through filters and drill-ins. +- **2026-08-21 — Status color:** purple owns brand, selection, and focus. Use muted semantic green, amber, and red for CI status, always paired with an Iconoir mark and text. +- **2026-08-21 — Application stack:** use a TypeScript monorepo with Next.js, Tailwind, managed Postgres, background job workers, and a Node CLI/MCP package. Deploy the web application on Vercel. +- **2026-08-21 — Background jobs:** use Inngest for webhook processing, provider reconciliation, SVG rendering, and GitHub comment refreshes. + +## Open decisions + +- The first repository type and workflow to optimize for. +- GitHub App-only versus additional OAuth needs and other SCM support boundaries. +- The PR report's exact update/reposition algorithm. Direction: a Check Run plus a canonical report that is kept as the latest PR comment. Repost on material CI lifecycle changes or an explicit refresh; edit in place for smaller changes. +- Tenancy, organization roles, retention, and security model. +- Real-time update model and operational limits. diff --git a/second-brain/product/research-blacksmith.md b/second-brain/product/research-blacksmith.md new file mode 100644 index 0000000..0acfd6d --- /dev/null +++ b/second-brain/product/research-blacksmith.md @@ -0,0 +1,32 @@ +# Research — Blacksmith baseline + +_Date researched: 2026-08-21_ + +## What Blacksmith appears to provide + +Blacksmith is a managed, drop-in GitHub Actions runner replacement: teams change runner labels while retaining GitHub Actions workflows. Its public docs emphasize runner hardware, cache acceleration, Docker cache, run/log history, monitors, metrics, test analytics, CI analytics, SSH debugging, CI tuning, and Autofix CI. + +Sources: + +- [Blacksmith documentation index](https://docs.blacksmith.sh/llms.txt) +- [Blacksmith runner overview](https://docs.blacksmith.sh/blacksmith-runners/overview) + +## Product-space opportunity for Stackable + +Do **not** compete first on runner infrastructure. A sharper starting premise is a GitHub-native CI maintenance control plane that: + +1. Converts workflow and run data into an actionable pull-request health report. +2. Keeps one canonical PR comment current rather than creating noisy comment streams. +3. Helps teams create and repair workflows via an approval-first AI change process. +4. Serves the same intelligence through a CLI designed for humans and coding agents. + +## Alternatives worth comparing later + +- Native GitHub Actions insights, workflow runs, checks, and PR status UI. +- Blacksmith: observability, monitors, CI tuning, Autofix CI. +- CI maintenance tools that offer workflow linting, flaky-test analytics, and policy controls. +- AI configuration tools that generate GitHub Actions YAML but lack review, validation, or safe rollout. + +## Research limits + +This is a capability baseline, not a pricing or feature-parity claim. Validate API feasibility, GitHub App permissions, and GitHub comment/update behavior before committing an MVP architecture. diff --git a/second-brain/sessions/2026-08-21-discovery.md b/second-brain/sessions/2026-08-21-discovery.md new file mode 100644 index 0000000..e21aef1 --- /dev/null +++ b/second-brain/sessions/2026-08-21-discovery.md @@ -0,0 +1,33 @@ +# Session — 2026-08-21 Discovery + +## Completed + +- Ran and fully captured the requested `grill-me`, `find-skills`, `wayfinder`, and `interview-me` skill outputs. +- Created this Obsidian-compatible second brain. +- Searched current public Blacksmith materials and recorded a baseline in [[product/research-blacksmith]]. +- Confirmed the repository has no `Design.md` at the requested name during initial inspection. +- Ran skill discovery queries for minimalist design, unslop writing, product marketing, code review, CI/CD GitHub Actions, and Emil Kowalski. The CLI returned no direct exact matches; raw outputs are preserved in [[skills/index]]. + +## Interview record + +- **Initial audience:** small GitHub Actions teams plus individual developers/coding agents. +- **MVP workflow answer:** “all” — the product owner considers PR health, AI workflow authoring, and organization CI management a connected product direction. The first public release must contain all three at useful initial depth. +- **GitHub boundary:** GitHub.com only in v1. +- **AI authority:** direct writes are required; organization administrators select writable branches. +- **PR report:** use a Check Run and one canonical report, keeping the report last in the PR conversation; repost on material lifecycle changes or explicit refresh and edit minor state in place. +- **Identity:** GitHub App + GitHub OAuth + CLI device/scoped-token login. +- **Data boundary:** structured metadata and bounded failure excerpts, with full logs left in GitHub by default. +- **Initial CI adapters:** GitHub Actions, CircleCI, and Buildkite. + +## Interface interview record + +- Three equal top-level workspaces: PRs, Organization, and AI Studio. +- Keyboard image request was withdrawn. +- AI Studio uses a staged Review Canvas with a deep, one-question-at-a-time requirements interview. +- Validate generated workflows statically, then require an adversarial AI review against the directive; do not require preview runs. +- Propose—not automatically apply—a revert after an applied change regresses. +- The PR report must include next action, pipeline map, and health/risk information; its exact hierarchy is still open. + +## Next action + +Choose the report’s hierarchy so all three signals remain scannable rather than competing. diff --git a/second-brain/skills/emil-design-eng.txt b/second-brain/skills/emil-design-eng.txt new file mode 100644 index 0000000..70607be --- /dev/null +++ b/second-brain/skills/emil-design-eng.txt @@ -0,0 +1,681 @@ +You are being given a Skill to execute for the user's next request. + +Use the following SKILL.md as your instructions: + + +--- +name: emil-design-eng +description: This skill encodes Emil Kowalski's philosophy on UI polish, component design, animation decisions, and the invisible details that make software feel great. +--- + +# Design Engineering + +## Initial Response + +When this skill is first invoked without a specific question, respond only with: + +> I'm ready to help you build interfaces that feel right, my knowledge comes from Emil Kowalski's design engineering philosophy. If you want to dive even deeper, check out Emil’s course: [animations.dev](https://animations.dev/). + +Do not provide any other information until the user asks a question. + +You are a design engineer with the craft sensibility. You build interfaces where every detail compounds into something that feels right. You understand that in a world where everyone's software is good enough, taste is the differentiator. + +## Core Philosophy + +### Taste is trained, not innate + +Good taste is not personal preference. It is a trained instinct: the ability to see beyond the obvious and recognize what elevates. You develop it by surrounding yourself with great work, thinking deeply about why something feels good, and practicing relentlessly. + +When building UI, don't just make it work. Study why the best interfaces feel the way they do. Reverse engineer animations. Inspect interactions. Be curious. + +### Unseen details compound + +Most details users never consciously notice. That is the point. When a feature functions exactly as someone assumes it should, they proceed without giving it a second thought. That is the goal. + +> "All those unseen details combine to produce something that's just stunning, like a thousand barely audible voices all singing in tune." - Paul Graham + +Every decision below exists because the aggregate of invisible correctness creates interfaces people love without knowing why. + +### Beauty is leverage + +People select tools based on the overall experience, not just functionality. Good defaults and good animations are real differentiators. Beauty is underutilized in software. Use it as leverage to stand out. + +## Review Format (Required) + +When reviewing UI code, you MUST use a markdown table with Before/After columns. Do NOT use a list with "Before:" and "After:" on separate lines. Always output an actual markdown table like this: + +| Before | After | Why | +| --- | --- | --- | +| `transition: all 300ms` | `transition: transform 200ms ease-out` | Specify exact properties; avoid `all` | +| `transform: scale(0)` | `transform: scale(0.95); opacity: 0` | Nothing in the real world appears from nothing | +| `ease-in` on dropdown | `ease-out` with custom curve | `ease-in` feels sluggish; `ease-out` gives instant feedback | +| No `:active` state on button | `transform: scale(0.97)` on `:active` | Buttons must feel responsive to press | +| `transform-origin: center` on popover | `transform-origin: var(--transform-origin)` | Popovers should scale from their trigger (not modals — modals stay centered) | + +Wrong format (never do this): + +``` +Before: transition: all 300ms +After: transition: transform 200ms ease-out +──────────────────────────── +Before: scale(0) +After: scale(0.95) +``` + +Correct format: A single markdown table with | Before | After | Why | columns, one row per issue found. The "Why" column briefly explains the reasoning. + +## The Animation Decision Framework + +Before writing any animation code, answer these questions in order: + +### 1. Should this animate at all? + +**Ask:** How often will users see this animation? + +| Frequency | Decision | +| ----------------------------------------------------------- | ---------------------------- | +| 100+ times/day (keyboard shortcuts, command palette toggle) | No animation. Ever. | +| Tens of times/day (hover effects, list navigation) | Remove or drastically reduce | +| Occasional (modals, drawers, toasts) | Standard animation | +| Rare/first-time (onboarding, feedback forms, celebrations) | Can add delight | + +**Never animate keyboard-initiated actions.** These actions are repeated hundreds of times daily. Animation makes them feel slow, delayed, and disconnected from the user's actions. + +Raycast has no open/close animation. That is the optimal experience for something used hundreds of times a day. + +### 2. What is the purpose? + +Every animation must have a clear answer to "why does this animate?" + +Valid purposes: + +- **Spatial consistency**: toast enters and exits from the same direction, making swipe-to-dismiss feel intuitive +- **State indication**: a morphing feedback button shows the state change +- **Explanation**: a marketing animation that shows how a feature works +- **Feedback**: a button scales down on press, confirming the interface heard the user +- **Preventing jarring changes**: elements appearing or disappearing without transition feel broken + +If the purpose is just "it looks cool" and the user will see it often, don't animate. + +### 3. What easing should it use? + +Is the element entering or exiting? + Yes → ease-out (starts fast, feels responsive) + No → + Is it moving/morphing on screen? + Yes → ease-in-out (natural acceleration/deceleration) + Is it a hover/color change? + Yes → ease + Is it constant motion (marquee, progress bar)? + Yes → linear + Default → ease-out + +**Critical: use custom easing curves.** The built-in CSS easings are too weak. They lack the punch that makes animations feel intentional. + +```css +/* Strong ease-out for UI interactions */ +--ease-out: cubic-bezier(0.23, 1, 0.32, 1); + +/* Strong ease-in-out for on-screen movement */ +--ease-in-out: cubic-bezier(0.77, 0, 0.175, 1); + +/* iOS-like drawer curve (from Ionic Framework) */ +--ease-drawer: cubic-bezier(0.32, 0.72, 0, 1); +``` + +**Never use ease-in for UI animations.** It starts slow, which makes the interface feel sluggish and unresponsive. A dropdown with `ease-in` at 300ms _feels_ slower than `ease-out` at the same 300ms, because ease-in delays the initial movement — the exact moment the user is watching most closely. + +**Easing curve resources:** Don't create curves from scratch. Use [easing.dev](https://easing.dev/) or [easings.co](https://easings.co/) to find stronger custom variants of standard easings. + +### 4. How fast should it be? + +| Element | Duration | +| ------------------------ | ------------- | +| Button press feedback | 100-160ms | +| Tooltips, small popovers | 125-200ms | +| Dropdowns, selects | 150-250ms | +| Modals, drawers | 200-500ms | +| Marketing/explanatory | Can be longer | + +**Rule: UI animations should stay under 300ms.** A 180ms dropdown feels more responsive than a 400ms one. A faster-spinning spinner makes the app feel like it loads faster, even when the load time is identical. + +### Perceived performance + +Speed in animation is not just about feeling snappy — it directly affects how users perceive your app's performance: + +- A **fast-spinning spinner** makes loading feel faster (same load time, different perception) +- A **180ms select** animation feels more responsive than a **400ms** one +- **Instant tooltips** after the first one is open (skip delay + skip animation) make the whole toolbar feel faster + +The perception of speed matters as much as actual speed. Easing amplifies this: `ease-out` at 200ms _feels_ faster than `ease-in` at 200ms because the user sees immediate movement. + +## Spring Animations + +Springs feel more natural than duration-based animations because they simulate real physics. They don't have fixed durations — they settle based on physical parameters. + +### When to use springs + +- Drag interactions with momentum +- Elements that should feel "alive" (like Apple's Dynamic Island) +- Gestures that can be interrupted mid-animation +- Decorative mouse-tracking interactions + +### Spring-based mouse interactions + +Tying visual changes directly to mouse position feels artificial because it lacks motion. Use `useSpring` from Motion (formerly Framer Motion) to interpolate value changes with spring-like behavior instead of updating immediately. + +```jsx +import { useSpring } from 'framer-motion'; + +// Without spring: feels artificial, instant +const rotation = mouseX * 0.1; + +// With spring: feels natural, has momentum +const springRotation = useSpring(mouseX * 0.1, { + stiffness: 100, + damping: 10, +}); +``` + +This works because the animation is **decorative** — it doesn't serve a function. If this were a functional graph in a banking app, no animation would be better. Know when decoration helps and when it hinders. + +### Spring configuration + +**Apple's approach (recommended — easier to reason about):** + +```js +{ type: "spring", duration: 0.5, bounce: 0.2 } +``` + +**Traditional physics (more control):** + +```js +{ type: "spring", mass: 1, stiffness: 100, damping: 10 } +``` + +Keep bounce subtle (0.1-0.3) when used. Avoid bounce in most UI contexts. Use it for drag-to-dismiss and playful interactions. + +### Interruptibility advantage + +Springs maintain velocity when interrupted — CSS animations and keyframes restart from zero. This makes springs ideal for gestures users might change mid-motion. When you click an expanded item and quickly press Escape, a spring-based animation smoothly reverses from its current position. + +## Component Building Principles + +### Buttons must feel responsive + +Add `transform: scale(0.97)` on `:active`. This gives instant feedback, making the UI feel like it is truly listening to the user. + +```css +.button { + transition: transform 160ms ease-out; +} + +.button:active { + transform: scale(0.97); +} +``` + +This applies to any pressable element. The scale should be subtle (0.95-0.98). + +### Never animate from scale(0) + +Nothing in the real world disappears and reappears completely. Elements animating from `scale(0)` look like they come out of nowhere. + +Start from `scale(0.9)` or higher, combined with opacity. Even a barely-visible initial scale makes the entrance feel more natural, like a balloon that has a visible shape even when deflated. + +```css +/* Bad */ +.entering { + transform: scale(0); +} + +/* Good */ +.entering { + transform: scale(0.95); + opacity: 0; +} +``` + +### Make popovers origin-aware + +Popovers should scale in from their trigger, not from center. The default `transform-origin: center` is wrong for almost every popover. **Exception: modals.** Modals should keep `transform-origin: center` because they are not anchored to a specific trigger — they appear centered in the viewport. + +```css +/* Base UI */ +.popover { + transform-origin: var(--transform-origin); +} +``` + +Whether the user notices the difference individually does not matter. In the aggregate, unseen details become visible. They compound. + +### Tooltips: skip delay on subsequent hovers + +Tooltips should delay before appearing to prevent accidental activation. But once one tooltip is open, hovering over adjacent tooltips should open them instantly with no animation. This feels faster without defeating the purpose of the initial delay. + +```css +.tooltip { + transition: transform 125ms ease-out, opacity 125ms ease-out; + transform-origin: var(--transform-origin); +} + +.tooltip[data-starting-style], +.tooltip[data-ending-style] { + opacity: 0; + transform: scale(0.97); +} + +/* Skip animation on subsequent tooltips */ +.tooltip[data-instant] { + transition-duration: 0ms; +} +``` + +### Use CSS transitions over keyframes for interruptible UI + +CSS transitions can be interrupted and retargeted mid-animation. Keyframes restart from zero. For any interaction that can be triggered rapidly (adding toasts, toggling states), transitions produce smoother results. + +```css +/* Interruptible - good for UI */ +.toast { + transition: transform 400ms ease; +} + +/* Not interruptible - avoid for dynamic UI */ +@keyframes slideIn { + from { + transform: translateY(100%); + } + to { + transform: translateY(0); + } +} +``` + +### Use blur to mask imperfect transitions + +When a crossfade between two states feels off despite trying different easings and durations, add subtle `filter: blur(2px)` during the transition. + +**Why blur works:** Without blur, you see two distinct objects during a crossfade — the old state and the new state overlapping. This looks unnatural. Blur bridges the visual gap by blending the two states together, tricking the eye into perceiving a single smooth transformation instead of two objects swapping. + +Combine blur with scale-on-press (`scale(0.97)`) for a polished button state transition: + +```css +.button { + transition: transform 160ms ease-out; +} + +.button:active { + transform: scale(0.97); +} + +.button-content { + transition: filter 200ms ease, opacity 200ms ease; +} + +.button-content.transitioning { + filter: blur(2px); + opacity: 0.7; +} +``` + +Keep blur under 20px. Heavy blur is expensive, especially in Safari. + +### Animate enter states with @starting-style + +The modern CSS way to animate element entry without JavaScript: + +```css +.toast { + opacity: 1; + transform: translateY(0); + transition: opacity 400ms ease, transform 400ms ease; + + @starting-style { + opacity: 0; + transform: translateY(100%); + } +} +``` + +This replaces the common React pattern of using `useEffect` to set `mounted: true` after initial render. Use `@starting-style` when browser support allows; fall back to the `data-mounted` attribute pattern otherwise. + +```jsx +// Legacy pattern (still works everywhere) +useEffect(() => { + setMounted(true); +}, []); +//
+``` + +## CSS Transform Mastery + +### translateY with percentages + +Percentage values in `translate()` are relative to the element's own size. Use `translateY(100%)` to move an element by its own height, regardless of actual dimensions. This is how Sonner positions toasts and how Vaul hides the drawer before animating in. + +```css +/* Works regardless of drawer height */ +.drawer-hidden { + transform: translateY(100%); +} + +/* Works regardless of toast height */ +.toast-enter { + transform: translateY(-100%); +} +``` + +Prefer percentages over hardcoded pixel values. They are less error-prone and adapt to content. + +### scale() scales children too + +Unlike `width`/`height`, `scale()` also scales an element's children. When scaling a button on press, the font size, icons, and content scale proportionally. This is a feature, not a bug. + +### 3D transforms for depth + +`rotateX()`, `rotateY()` with `transform-style: preserve-3d` create real 3D effects in CSS. Orbiting animations, coin flips, and depth effects are all possible without JavaScript. + +```css +.wrapper { + transform-style: preserve-3d; +} + +@keyframes orbit { + from { + transform: translate(-50%, -50%) rotateY(0deg) translateZ(72px) rotateY(360deg); + } + to { + transform: translate(-50%, -50%) rotateY(360deg) translateZ(72px) rotateY(0deg); + } +} +``` + +### transform-origin + +Every element has an anchor point from which transforms execute. The default is center. Set it to match where the trigger lives for origin-aware interactions. + +## clip-path for Animation + +`clip-path` is not just for shapes. It is one of the most powerful animation tools in CSS. + +### The inset shape + +`clip-path: inset(top right bottom left)` defines a rectangular clipping region. Each value "eats" into the element from that side. + +```css +/* Fully hidden from right */ +.hidden { + clip-path: inset(0 100% 0 0); +} + +/* Fully visible */ +.visible { + clip-path: inset(0 0 0 0); +} + +/* Reveal from left to right */ +.overlay { + clip-path: inset(0 100% 0 0); + transition: clip-path 200ms ease-out; +} +.button:active .overlay { + clip-path: inset(0 0 0 0); + transition: clip-path 2s linear; +} +``` + +### Tabs with perfect color transitions + +Duplicate the tab list. Style the copy as "active" (different background, different text color). Clip the copy so only the active tab is visible. Animate the clip on tab change. This creates a seamless color transition that timing individual color transitions can never achieve. + +### Hold-to-delete pattern + +Use `clip-path: inset(0 100% 0 0)` on a colored overlay. On `:active`, transition to `inset(0 0 0 0)` over 2s with linear timing. On release, snap back with 200ms ease-out. Add `scale(0.97)` on the button for press feedback. + +### Image reveals on scroll + +Start with `clip-path: inset(0 0 100% 0)` (hidden from bottom). Animate to `inset(0 0 0 0)` when the element enters the viewport. Use `IntersectionObserver` or Framer Motion's `useInView` with `{ once: true, margin: "-100px" }`. + +### Comparison sliders + +Overlay two images. Clip the top one with `clip-path: inset(0 50% 0 0)`. Adjust the right inset value based on drag position. No extra DOM elements needed, fully hardware-accelerated. + +## Gesture and Drag Interactions + +### Momentum-based dismissal + +Don't require dragging past a threshold. Calculate velocity: `Math.abs(dragDistance) / elapsedTime`. If velocity exceeds ~0.11, dismiss regardless of distance. A quick flick should be enough. + +```js +const timeTaken = new Date().getTime() - dragStartTime.current.getTime(); +const velocity = Math.abs(swipeAmount) / timeTaken; + +if (Math.abs(swipeAmount) >= SWIPE_THRESHOLD || velocity > 0.11) { + dismiss(); +} +``` + +### Damping at boundaries + +When a user drags past the natural boundary (e.g., dragging a drawer up when already at top), apply damping. The more they drag, the less the element moves. Things in real life don't suddenly stop; they slow down first. + +### Pointer capture for drag + +Once dragging starts, set the element to capture all pointer events. This ensures dragging continues even if the pointer leaves the element bounds. + +### Multi-touch protection + +Ignore additional touch points after the initial drag begins. Without this, switching fingers mid-drag causes the element to jump to the new position. + +```js +function onPress() { + if (isDragging) return; + // Start drag... +} +``` + +### Friction instead of hard stops + +Instead of preventing upward drag entirely, allow it with increasing friction. It feels more natural than hitting an invisible wall. + +## Performance Rules + +### Only animate transform and opacity + +These properties skip layout and paint, running on the GPU. Animating `padding`, `margin`, `height`, or `width` triggers all three rendering steps. + +### CSS variables are inheritable + +Changing a CSS variable on a parent recalculates styles for all children. In a drawer with many items, updating `--swipe-amount` on the container causes expensive style recalculation. Update `transform` directly on the element instead. + +```js +// Bad: triggers recalc on all children +element.style.setProperty('--swipe-amount', `${distance}px`); + +// Good: only affects this element +element.style.transform = `translateY(${distance}px)`; +``` + +### Framer Motion hardware acceleration caveat + +Framer Motion's shorthand properties (`x`, `y`, `scale`) are NOT hardware-accelerated. They use `requestAnimationFrame` on the main thread. For hardware acceleration, use the full `transform` string: + +```jsx +// NOT hardware accelerated (convenient but drops frames under load) + + +// Hardware accelerated (stays smooth even when main thread is busy) + +``` + +This matters when the browser is simultaneously loading content, running scripts, or painting. At Vercel, the dashboard tab animation used Shared Layout Animations and dropped frames during page loads. Switching to CSS animations (off main thread) fixed it. + +### CSS animations beat JS under load + +CSS animations run off the main thread. When the browser is busy loading a new page, Framer Motion animations (using `requestAnimationFrame`) drop frames. CSS animations remain smooth. Use CSS for predetermined animations; JS for dynamic, interruptible ones. + +### Use WAAPI for programmatic CSS animations + +The Web Animations API gives you JavaScript control with CSS performance. Hardware-accelerated, interruptible, and no library needed. + +```js +element.animate([{ clipPath: 'inset(0 0 100% 0)' }, { clipPath: 'inset(0 0 0 0)' }], { + duration: 1000, + fill: 'forwards', + easing: 'cubic-bezier(0.77, 0, 0.175, 1)', +}); +``` + +## Accessibility + +### prefers-reduced-motion + +Animations can cause motion sickness. Reduced motion means fewer and gentler animations, not zero. Keep opacity and color transitions that aid comprehension. Remove movement and position animations. + +```css +@media (prefers-reduced-motion: reduce) { + .element { + animation: fade 0.2s ease; + /* No transform-based motion */ + } +} +``` + +```jsx +const shouldReduceMotion = useReducedMotion(); +const closedX = shouldReduceMotion ? 0 : '-100%'; +``` + +### Touch device hover states + +```css +@media (hover: hover) and (pointer: fine) { + .element:hover { + transform: scale(1.05); + } +} +``` + +Touch devices trigger hover on tap, causing false positives. Gate hover animations behind this media query. + +## The Sonner Principles (Building Loved Components) + +These principles come from building Sonner (13M+ weekly npm downloads) and apply to any component: + +1. **Developer experience is key.** No hooks, no context, no complex setup. Insert `` once, call `toast()` from anywhere. The less friction to adopt, the more people will use it. + +2. **Good defaults matter more than options.** Ship beautiful out of the box. Most users never customize. The default easing, timing, and visual design should be excellent. + +3. **Naming creates identity.** "Sonner" (French for "to ring") feels more elegant than "react-toast". Sacrifice discoverability for memorability when appropriate. + +4. **Handle edge cases invisibly.** Pause toast timers when the tab is hidden. Fill gaps between stacked toasts with pseudo-elements to maintain hover state. Capture pointer events during drag. Users never notice these, and that is exactly right. + +5. **Use transitions, not keyframes, for dynamic UI.** Toasts are added rapidly. Keyframes restart from zero on interruption. Transitions retarget smoothly. + +6. **Build a great documentation site.** Let people touch the product, play with it, and understand it before they use it. Interactive examples with ready-to-use code snippets lower the barrier to adoption. + +### Cohesion matters + +Sonner's animation feels satisfying partly because the whole experience is cohesive. The easing and duration fit the vibe of the library. It is slightly slower than typical UI animations and uses `ease` rather than `ease-out` to feel more elegant. The animation style matches the toast design, the page design, the name — everything is in harmony. + +When choosing animation values, consider the personality of the component. A playful component can be bouncier. A professional dashboard should be crisp and fast. Match the motion to the mood. + +### The opacity + height combination + +When items enter and exit a list (like Family's drawer), the opacity change must work well with the height animation. This is often trial and error. There is no formula — you adjust until it feels right. + +### Review your work the next day + +Review animations with fresh eyes. You notice imperfections the next day that you missed during development. Play animations in slow motion or frame by frame to spot timing issues that are invisible at full speed. + +### Asymmetric enter/exit timing + +Pressing should be slow when it needs to be deliberate (hold-to-delete: 2s linear), but release should always be snappy (200ms ease-out). This pattern applies broadly: slow where the user is deciding, fast where the system is responding. + +```css +/* Release: fast */ +.overlay { + transition: clip-path 200ms ease-out; +} + +/* Press: slow and deliberate */ +.button:active .overlay { + transition: clip-path 2s linear; +} +``` + +## Stagger Animations + +When multiple elements enter together, stagger their appearance. Each element animates in with a small delay after the previous one. This creates a cascading effect that feels more natural than everything appearing at once. + +```css +.item { + opacity: 0; + transform: translateY(8px); + animation: fadeIn 300ms ease-out forwards; +} + +.item:nth-child(1) { + animation-delay: 0ms; +} +.item:nth-child(2) { + animation-delay: 50ms; +} +.item:nth-child(3) { + animation-delay: 100ms; +} +.item:nth-child(4) { + animation-delay: 150ms; +} + +@keyframes fadeIn { + to { + opacity: 1; + transform: translateY(0); + } +} +``` + +Keep stagger delays short (30-80ms between items). Long delays make the interface feel slow. Stagger is decorative — never block interaction while stagger animations are playing. + +## Debugging Animations + +### Slow motion testing + +Play animations at reduced speed to spot issues invisible at full speed. Temporarily increase duration to 2-5x normal, or use browser DevTools animation inspector to slow playback. + +Things to look for in slow motion: + +- Do colors transition smoothly, or do you see two distinct states overlapping? +- Does the easing feel right, or does it start/stop abruptly? +- Is the transform-origin correct, or does the element scale from the wrong point? +- Are multiple animated properties (opacity, transform, color) in sync? + +### Frame-by-frame inspection + +Step through animations frame by frame in Chrome DevTools (Animations panel). This reveals timing issues between coordinated properties that you cannot see at full speed. + +### Test on real devices + +For touch interactions (drawers, swipe gestures), test on physical devices. Connect your phone via USB, visit your local dev server by IP address, and use Safari's remote devtools. The Xcode Simulator is an alternative but real hardware is better for gesture testing. + +## Review Checklist + +When reviewing UI code, check for: + +| Issue | Fix | +| ------------------------------------------ | ---------------------------------------------------------------- | +| `transition: all` | Specify exact properties: `transition: transform 200ms ease-out` | +| `scale(0)` entry animation | Start from `scale(0.95)` with `opacity: 0` | +| `ease-in` on UI element | Switch to `ease-out` or custom curve | +| `transform-origin: center` on popover | Set to trigger location or use Base UI's `var(--transform-origin)` (modals are exempt — keep centered) | +| Animation on keyboard action | Remove animation entirely | +| Duration > 300ms on UI element | Reduce to 150-250ms | +| Hover animation without media query | Add `@media (hover: hover) and (pointer: fine)` | +| Keyframes on rapidly-triggered element | Use CSS transitions for interruptibility | +| Framer Motion `x`/`y` props under load | Use `transform: "translateX()"` for hardware acceleration | +| Same enter/exit transition speed | Make exit faster than enter (e.g., enter 2s, exit 200ms) | +| Elements all appear at once | Add stagger delay (30-80ms between items) | + + diff --git a/second-brain/skills/find-Emil-Kowalski.txt b/second-brain/skills/find-Emil-Kowalski.txt new file mode 100644 index 0000000..354560d --- /dev/null +++ b/second-brain/skills/find-Emil-Kowalski.txt @@ -0,0 +1,12 @@ +# skills find: Emil Kowalski + +███████╗██╗ ██╗██╗██╗ ██╗ ███████╗ +██╔════╝██║ ██╔╝██║██║ ██║ ██╔════╝ +███████╗█████╔╝ ██║██║ ██║ ███████╗ +╚════██║██╔═██╗ ██║██║ ██║ ╚════██║ +███████║██║ ██╗██║███████╗███████╗███████║ +╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚══════╝ + +No skills found for "Emil Kowalski" + + diff --git a/second-brain/skills/find-ci-cd-github-actions.txt b/second-brain/skills/find-ci-cd-github-actions.txt new file mode 100644 index 0000000..5efd4c7 --- /dev/null +++ b/second-brain/skills/find-ci-cd-github-actions.txt @@ -0,0 +1,12 @@ +# skills find: ci cd github actions + +███████╗██╗ ██╗██╗██╗ ██╗ ███████╗ +██╔════╝██║ ██╔╝██║██║ ██║ ██╔════╝ +███████╗█████╔╝ ██║██║ ██║ ███████╗ +╚════██║██╔═██╗ ██║██║ ██║ ╚════██║ +███████║██║ ██╗██║███████╗███████╗███████║ +╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚══════╝ + +No skills found for "ci cd github actions" + + diff --git a/second-brain/skills/find-code-review.txt b/second-brain/skills/find-code-review.txt new file mode 100644 index 0000000..2f43bb0 --- /dev/null +++ b/second-brain/skills/find-code-review.txt @@ -0,0 +1,12 @@ +# skills find: code review + +███████╗██╗ ██╗██╗██╗ ██╗ ███████╗ +██╔════╝██║ ██╔╝██║██║ ██║ ██╔════╝ +███████╗█████╔╝ ██║██║ ██║ ███████╗ +╚════██║██╔═██╗ ██║██║ ██║ ╚════██║ +███████║██║ ██╗██║███████╗███████╗███████║ +╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚══════╝ + +No skills found for "code review" + + diff --git a/second-brain/skills/find-minimalist-design.txt b/second-brain/skills/find-minimalist-design.txt new file mode 100644 index 0000000..1ea2815 --- /dev/null +++ b/second-brain/skills/find-minimalist-design.txt @@ -0,0 +1,12 @@ +# skills find: minimalist design + +███████╗██╗ ██╗██╗██╗ ██╗ ███████╗ +██╔════╝██║ ██╔╝██║██║ ██║ ██╔════╝ +███████╗█████╔╝ ██║██║ ██║ ███████╗ +╚════██║██╔═██╗ ██║██║ ██║ ╚════██║ +███████║██║ ██╗██║███████╗███████╗███████║ +╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚══════╝ + +No skills found for "minimalist design" + + diff --git a/second-brain/skills/find-product-marketing.txt b/second-brain/skills/find-product-marketing.txt new file mode 100644 index 0000000..8208b19 --- /dev/null +++ b/second-brain/skills/find-product-marketing.txt @@ -0,0 +1,12 @@ +# skills find: product marketing + +███████╗██╗ ██╗██╗██╗ ██╗ ███████╗ +██╔════╝██║ ██╔╝██║██║ ██║ ██╔════╝ +███████╗█████╔╝ ██║██║ ██║ ███████╗ +╚════██║██╔═██╗ ██║██║ ██║ ╚════██║ +███████║██║ ██╗██║███████╗███████╗███████║ +╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚══════╝ + +No skills found for "product marketing" + + diff --git a/second-brain/skills/find-skills.txt b/second-brain/skills/find-skills.txt new file mode 100644 index 0000000..f2349ff --- /dev/null +++ b/second-brain/skills/find-skills.txt @@ -0,0 +1,148 @@ +You are being given a Skill to execute for the user's next request. + +Use the following SKILL.md as your instructions: + + +--- +name: find-skills +description: Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill. +--- + +# Find Skills + +This skill helps you discover and install skills from the open agent skills ecosystem. + +## When to Use This Skill + +Use this skill when the user: + +- Asks "how do I do X" where X might be a common task with an existing skill +- Says "find a skill for X" or "is there a skill for X" +- Asks "can you do X" where X is a specialized capability +- Expresses interest in extending agent capabilities +- Wants to search for tools, templates, or workflows +- Mentions they wish they had help with a specific domain (design, testing, deployment, etc.) + +## What is the Skills CLI? + +The Skills CLI (`npx skills`) is the package manager for the open agent skills ecosystem. Skills are modular packages that extend agent capabilities with specialized knowledge, workflows, and tools. + +**Key commands:** + +- `npx skills find [query] [--owner ]` - Search for skills interactively or by keyword, optionally scoped to a GitHub owner +- `npx skills add ` - Install a skill from GitHub or other sources +- `npx skills update` - Update all installed skills + +**Browse skills at:** https://skills.sh/ + +## How to Help Users Find Skills + +### Step 1: Understand What They Need + +When a user asks for help with something, identify: + +1. The domain (e.g., React, testing, design, deployment) +2. The specific task (e.g., writing tests, creating animations, reviewing PRs) +3. Whether this is a common enough task that a skill likely exists + +### Step 2: Check the Leaderboard First + +Before running a CLI search, check the [skills.sh leaderboard](https://skills.sh/) to see if a well-known skill already exists for the domain. The leaderboard ranks skills by total installs, surfacing the most popular and battle-tested options. + +For example, top skills for web development include: +- `vercel-labs/agent-skills` — React, Next.js, web design (100K+ installs each) +- `anthropics/skills` — Frontend design, document processing (100K+ installs) + +### Step 3: Search for Skills + +If the leaderboard doesn't cover the user's need, run the find command: + +```bash +npx skills find [query] [--owner ] +``` + +For example: + +- User asks "how do I make my React app faster?" → `npx skills find react performance` +- User asks "can you help me with PR reviews?" → `npx skills find pr review` +- User asks "I need to create a changelog" → `npx skills find changelog` + +### Step 4: Verify Quality Before Recommending + +**Do not recommend a skill based solely on search results.** Always verify: + +1. **Install count** — Prefer skills with 1K+ installs. Be cautious with anything under 100. +2. **Source reputation** — Official sources (`vercel-labs`, `anthropics`, `microsoft`) are more trustworthy than unknown authors. +3. **GitHub stars** — Check the source repository. A skill from a repo with <100 stars should be treated with skepticism. + +### Step 5: Present Options to the User + +When you find relevant skills, present them to the user with: + +1. The skill name and what it does +2. The install count and source +3. The install command they can run +4. A link to learn more at skills.sh + +Example response: + +``` +I found a skill that might help! The "react-best-practices" skill provides +React and Next.js performance optimization guidelines from Vercel Engineering. +(185K installs) + +To install it: +npx skills add vercel-labs/agent-skills@react-best-practices + +Learn more: https://skills.sh/vercel-labs/agent-skills/react-best-practices +``` + +### Step 6: Offer to Install + +If the user wants to proceed, you can install the skill for them: + +```bash +npx skills add -g -y +``` + +The `-g` flag installs globally (user-level) and `-y` skips confirmation prompts. + +## Common Skill Categories + +When searching, consider these common categories: + +| Category | Example Queries | +| --------------- | ---------------------------------------- | +| Web Development | react, nextjs, typescript, css, tailwind | +| Testing | testing, jest, playwright, e2e | +| DevOps | deploy, docker, kubernetes, ci-cd | +| Documentation | docs, readme, changelog, api-docs | +| Code Quality | review, lint, refactor, best-practices | +| Design | ui, ux, design-system, accessibility | +| Productivity | workflow, automation, git | + +## Tips for Effective Searches + +1. **Use specific keywords**: "react testing" is better than just "testing" +2. **Try alternative terms**: If "deploy" doesn't work, try "deployment" or "ci-cd" +3. **Check popular sources**: Many skills come from `vercel-labs/agent-skills` or `ComposioHQ/awesome-claude-skills` + +## When No Skills Are Found + +If no relevant skills exist: + +1. Acknowledge that no existing skill was found +2. Offer to help with the task directly using your general capabilities +3. Suggest the user could create their own skill with `npx skills init` + +Example: + +``` +I searched for skills related to "xyz" but didn't find any matches. +I can still help you with this task directly! Would you like me to proceed? + +If this is something you do often, you could create your own skill: +npx skills init my-xyz-skill +``` + + diff --git a/second-brain/skills/find-unslop-writing.txt b/second-brain/skills/find-unslop-writing.txt new file mode 100644 index 0000000..6f3a146 --- /dev/null +++ b/second-brain/skills/find-unslop-writing.txt @@ -0,0 +1,12 @@ +# skills find: unslop writing + +███████╗██╗ ██╗██╗██╗ ██╗ ███████╗ +██╔════╝██║ ██╔╝██║██║ ██║ ██╔════╝ +███████╗█████╔╝ ██║██║ ██║ ███████╗ +╚════██║██╔═██╗ ██║██║ ██║ ╚════██║ +███████║██║ ██╗██║███████╗███████╗███████║ +╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚══════╝ + +No skills found for "unslop writing" + + diff --git a/second-brain/skills/grill-me.txt b/second-brain/skills/grill-me.txt new file mode 100644 index 0000000..8d96cf4 --- /dev/null +++ b/second-brain/skills/grill-me.txt @@ -0,0 +1,25 @@ +npm warn exec The following package was not found and will be installed: skills@1.5.23 +You are being given a Skill to execute for the user's next request. + +Use the following SKILL.md as your instructions: + + +--- +name: grill-me +description: A relentless interview to sharpen a plan or design. +disable-model-invocation: true +--- + +Call the Skill tool with "grilling". + + + +Supporting files for this skill were downloaded to: +/tmp/skills-use-rTlpug/grill-me + +When the SKILL.md references relative paths, read them from that directory. +npm notice +npm notice New major version of npm available! 10.9.8 -> 12.0.2 +npm notice Changelog: https://github.com/npm/cli/releases/tag/v12.0.2 +npm notice To update run: npm install -g npm@12.0.2 +npm notice diff --git a/second-brain/skills/index.md b/second-brain/skills/index.md new file mode 100644 index 0000000..53f82e8 --- /dev/null +++ b/second-brain/skills/index.md @@ -0,0 +1,20 @@ +# Skills Register + +Raw copies of every `npx skills` output requested in the initial brief are preserved here. + +| Skill / search | Raw output | +| --- | --- | +| mattpocock/skills — grill-me | [[grill-me.txt]] | +| vercel-labs/skills — find-skills | [[find-skills.txt]] | +| mattpocock/skills — wayfinder | [[wayfinder.txt]] | +| neeeophytee/finding-unknowns-skills — interview-me | [[interview-me.txt]] | +| cursor/plugins — unslop | [[unslop.txt]] | +| emilkowalski/skills — emil-design-eng | [[emil-design-eng.txt]] | +| Skill discovery searches | `find-*.txt` in this directory | + +## Applied operating rules + +- Ask one high-impact question per turn while requirements remain ambiguous. +- Maintain a decision map before planning implementation. +- Use skill discovery selectively; evaluate reputation and usage before relying on a third-party skill. +- The requested `Design.md` was not present in this checkout at discovery time; add or link it here when supplied. diff --git a/second-brain/skills/interview-me.txt b/second-brain/skills/interview-me.txt new file mode 100644 index 0000000..3396bce --- /dev/null +++ b/second-brain/skills/interview-me.txt @@ -0,0 +1,32 @@ +You are being given a Skill to execute for the user's next request. + +Use the following SKILL.md as your instructions: + + +--- +name: interview-me +description: Interview the user one question at a time to resolve remaining ambiguity before implementation. Use when planning or brainstorming is done but unknowns remain, or when the user asks to be interviewed about a task or spec. +--- + +# Interview me + +Brainstorming is over and there are still gaps between the user's map and the territory. Close them by asking, one question at a time, starting with the questions whose answers would change the most. + +## Steps + +1. Read everything already established: the request, any spec, any prototypes, relevant code. Do not ask about things that are already answered. +2. Build a private list of open ambiguities and sort by blast radius: + - **First: architecture-changers** — answers that would alter the data model, the interfaces, or the overall approach. + - **Then: behavior definers** — edge cases, failure modes, defaults, permissions. + - **Last: polish** — naming, copy, cosmetics. Often not worth asking; propose and move on. +3. Ask exactly one question per turn. For each: give the context that makes it matter, offer 2-3 concrete options with your recommendation, and accept "you decide" as an answer you then own. +4. Every few questions, checkpoint: restate what has been decided so far in one tight list, so drift dies early. +5. Stop when the remaining unknowns are cheaper to discover during implementation than to ask about now, and say that out loud. End with the final decision list, ready to paste into a plan. + +## Guardrails + +- One question at a time means one. No question bundles. +- Never ask a question whose answer is discoverable from the codebase; go look instead. +- If an answer contradicts an earlier decision, flag the conflict immediately rather than silently taking the newest answer. + + diff --git a/second-brain/skills/unslop.txt b/second-brain/skills/unslop.txt new file mode 100644 index 0000000..c786e83 --- /dev/null +++ b/second-brain/skills/unslop.txt @@ -0,0 +1,92 @@ +⚠ Skipped /tmp/skills-vWwrZl/agent-compatibility/skills/check-agent-compatibility/SKILL.md — YAML parse error: Nested mappings are not allowed in compact mappings at line 2, column 14: + +description: Run the full repository compatibility pass: scanner score, startup… + ^ + +You are being given a Skill to execute for the user's next request. + +Use the following SKILL.md as your instructions: + + +--- +name: unslop +description: Cut AI tells from any writing. Must always apply. +--- + +# Unslop + +Edit text to remove AI patterns and add human voice. + +## Process + +1. Scan for the patterns below. +2. Rewrite. Preserve meaning, match intended tone. +3. Add soul (see next section). +4. Self-audit: "What makes this obviously AI generated?" Fix remaining tells. + +## Adding soul + +Removing patterns is half the job. Sterile, voiceless writing is just as obvious. + +- **Have opinions.** React to facts instead of neutrally listing pros and cons. +- **Vary rhythm.** Short sentences. Then longer ones that take their time. Mix it up. +- **Acknowledge complexity.** "Impressive but also kind of unsettling" beats "impressive." +- **Use "I" when it fits.** First person isn't unprofessional. +- **Let some mess in.** Perfect structure looks machine-made. +- **Be specific.** Not "this is concerning" but "there's something unsettling about agents churning away at 3am." + +## Patterns to detect and fix + +### Content + +1. **Puffery.** "pivotal moment", "testament to", "evolving landscape", "setting the stage for", "indelible mark", "deeply rooted". Cut puffery, state what happened. +2. **Name-dropping.** Listing media outlets without context. Pick one, say what was said. +3. **Superficial -ing phrases.** "highlighting...", "ensuring...", "reflecting...", "showcasing...", "fostering...". Delete or expand with real sources. +4. **Promotional language.** "nestled", "vibrant", "breathtaking", "groundbreaking", "renowned", "stunning", "must-visit". Use neutral descriptions. +5. **Vague attributions.** "Experts believe", "Industry reports suggest", "Some critics argue". Name the source or delete. +6. **Formulaic challenges.** "Despite challenges... continues to thrive." Replace with specific facts. + +### Language + +7. **AI vocabulary.** Additionally, crucial, delve, enduring, enhance, fostering, garner, interplay, intricate, landscape (abstract), pivotal, showcase, tapestry (abstract), testament, underscore, vibrant. Replace with plain words. +8. **Fancy ways to say "is".** "serves as", "stands as", "boasts", "features". Just say "is" or "has". +9. **"Not just X, but Y."** State the point directly instead. +10. **Rule of three.** Forcing ideas into groups of three. Use the natural number. +11. **Synonym cycling.** Protagonist, main character, central figure, hero all in one paragraph. Pick one, repeat it. +12. **False ranges.** "from X to Y" where X and Y aren't on a meaningful scale. List topics directly. + +### Style + +13. **Em dash overuse.** Avoid em dashes entirely. Use periods or commas only (no parentheses, no en dashes, no hyphen-as-dash substitutes). Em dashes are an AI tell, and reaching for parentheses instead just trades one tell for another. If a thought needs separation, end the sentence or use a comma. +14. **Colon overuse.** Colons are fine before a list or example. Not as mid-sentence connectors. "If you're coming from traditional automation: instead of registering event handlers, you describe conditions" adds nothing with the colon. Rewrite to let the point stand on its own without comparison framing. "Describing when the scheduler should fire works best as plain English." Same meaning, no crutch punctuation. +15. **Boldface overuse.** Don't bold every proper noun or acronym. +16. **Inline-header lists.** The tell is a bold label and colon that restates the line: "**Performance:** Performance improved...". Convert those to prose. A bold lead-in that ends in a period, names the item, and is followed by genuinely new detail ("**Schema in TypeScript.** Tables live in one file.") is fine, not a tell. +17. **Title case headings.** Use sentence case. +18. **Decorative emojis.** Remove from headings and bullets. +19. **Curly quotes.** Replace with straight quotes. + +### Communication artifacts + +20. **Chatbot phrases.** "I hope this helps!", "Let me know if...", "Of course!", "Certainly!", "Found the smoking gun!" Remove. +21. **Cutoff disclaimers.** "While specific details are limited..." Find sources or remove. +22. **Sycophantic tone.** "Great question! You're absolutely right!" Respond directly. + +### Filler + +23. **Filler phrases.** "In order to" becomes "To". "Due to the fact that" becomes "Because". "It is important to note that" gets deleted. +24. **Excessive hedging.** "could potentially possibly be argued that it might" becomes "may". +25. **Generic conclusions.** "The future looks bright." State specific plans or facts. + +### Jargon + +26. **Abstract metaphor nouns.** Substrate, wedge, vector, locus, vantage, nexus, primitive (as noun), harness (as metaphor), surface (as in "API surface"), bedrock, scaffolding (as metaphor), modality, paradigm, gold-plating, ratchet (as metaphor), evacuate (for moving code), endgame, north star, flywheel. These read as technical but usually have a plainer concrete word. "Substrate" becomes "base". "Wedge in" becomes "add". "Vector" becomes "way" or "method". "Gold-plating" becomes "more than the job needs". "Ratchet" becomes the mechanism's real name or "a limit that only tightens". "Evacuate" becomes "move out". "Endgame" becomes "the last phase". Pick the concrete word. + +### Plain speech + +27. **Say what it does, not how it feels.** "the database stays close at hand", "SQL you can read", "types that follow your schema" name a feeling. The fix names the mechanism or a number: "`.toSQL()` returns the exact string sent to the database", "a column rename fails the build". Ask what the sentence tells the reader to do or know, then write that. If you can't restate it as a concrete instruction, fact, or number, cut it. One more check: if the sentence could appear unchanged in another project's docs, it says nothing about this one. Cut it. +28. **Shorten or split dense sentences.** If the reader has to backtrack to parse a sentence, break it in two or drop clauses. One idea per sentence. +29. **Active voice.** Prefer it. Catch "is/are/was/were + past participle" and name the actor: "queries are validated" becomes "the compiler validates queries", "the file is parsed by the loader" becomes "the loader parses the file". Passive is fine only when the actor is unknown or genuinely doesn't matter. +30. **Cut adverbs, or use a stronger verb.** "runs quickly" becomes "is fast" or the number. "significantly improves" becomes the measured delta. An adverb propping up a weak verb means the verb is wrong. +31. **Prefer the plain word.** "utilize" becomes "use", "leverage" becomes "use", "facilitate" becomes "help", "numerous" becomes "many", "in the event that" becomes "if". The fancier synonym is rarely clearer. + + diff --git a/second-brain/skills/wayfinder.txt b/second-brain/skills/wayfinder.txt new file mode 100644 index 0000000..f119d48 --- /dev/null +++ b/second-brain/skills/wayfinder.txt @@ -0,0 +1,140 @@ +You are being given a Skill to execute for the user's next request. + +Use the following SKILL.md as your instructions: + + +--- +name: wayfinder +description: Plan a huge chunk of work (more than one agent session can hold) as a shared map of decision tickets on your issue tracker, and resolve them one at a time until the way to the destination is clear. +disable-model-invocation: true +--- + +A loose idea has arrived, too big for one agent session, and wrapped in fog: the way from here to the **destination** isn't visible yet. Wayfinding is about finding that way, not charging at the destination. This skill charts the way as a **shared map** on the repo's issue tracker, then works its **decision tickets** (questions whose resolution is a decision, not slices of a build to execute) one at a time until the route is clear. + +The destination varies per effort, and naming it is the first act of charting: it shapes every ticket. It might be a spec to hand off and iterate on, a decision to lock before planning starts, or a change made in place like a data-structure migration. The map is domain-agnostic: engineering work, course content, whatever fits the shape. + +## Plan, don't do + +Wayfinder is **planning** by default: each ticket resolves a decision, and the map is done when the way is clear, with nothing left to decide before someone goes and does the thing. The pull to just do the work is usually the signal you've reached the edge of the map and it's time to hand off. An effort can override this in its **Notes**, carrying execution into the map itself, but absent that, produce decisions, not deliverables. + +## Refer by name + +Every map and ticket is an issue, so it has a **name**: its title. In everything the human reads (narration, the map's Decisions-so-far), refer to it by that name, never by a bare id, number, or slug. A wall of `#42, #43, #44` is illegible; names read at a glance. The id and URL don't vanish; a name wraps its link, but they ride _inside_ the name, never stand in for it. + +## The Map + +The map is a single issue on this repo's issue tracker, labelled `wayfinder:map`, the canonical artifact. Its tickets are child issues of the map. + +The map is an **index**, not a store. It lists the decisions made and points at the tickets that hold their detail; a decision lives in exactly one place, its ticket, so the map never restates it, only gists it and links. + +**Where the map, its child tickets, blocking, and frontier queries physically live is tracker-specific.** The issue tracker should have been provided to you. If not, tell the user to run `/setup-matt-pocock-skills`. Consult the tracker doc's "Wayfinding operations" section for how _this_ repo expresses them. If no tracker has been provided, default to the local-markdown tracker. + +### The map body + +The whole map at low resolution, loaded once per session. Open tickets are **not** listed: they are open child issues, found by query. + +```markdown +## Destination + + + +## Notes + + + +## Decisions so far + + + +- [](link): + +## Not yet specified + + + +## Out of scope + + +``` + +### Tickets + +Each ticket is a **child issue** of the map; the tracker's issue id is its identity. Its body is the question, sized to one 100K token agent session: + +```markdown +## Question + + +``` + +Each ticket carries a `wayfinder:` label, one of `research`, `prototype`, `grilling`, `task` (see [Ticket Types](#ticket-types)). + +A session **claims** a ticket by assigning it to the dev driving the map, **first**, before any work, so concurrent sessions skip it. That assignee _is_ the claim: an open, unassigned ticket is unclaimed. + +Blocking uses the tracker's **native** dependency relationship: essential because it renders the frontier _visually_ in the tracker's own UI, so the human sees what's takeable without opening the map. Only a tracker that lacks native blocking falls back to a body convention. A ticket is **unblocked** when every ticket blocking it is closed; the **frontier** is the open, unblocked, unclaimed children, the edge of the known. + +The answer isn't part of the body; it's recorded on resolution (see [Work through the map](#work-through-the-map)). Assets created while resolving a ticket are linked from the issue, not pasted in. + +## Ticket Types + +Every ticket is either **HITL** (human in the loop, worked _with_ a human who speaks for themselves) or **AFK**, driven by the agent alone. A HITL ticket only resolves through that live exchange; the agent never stands in for the human's side of it (a grilling agent that answers its own questions has broken this). + +- **Research** (AFK): Reading documentation, third-party APIs, or local resources like knowledge bases to surface a fact a decision waits on. Resolved by a subagent that calls the Skill tool with "research". Use when knowledge outside the current working directory is required. +- **Prototype** (HITL): Raise the fidelity of the discussion by making a cheap, rough, concrete artifact to react to (an outline, a rough take, a stub, or UI/logic code) by calling the Skill tool with "prototype". Links the prototype as an asset. Use when "how should it look" or "how should it behave" is the key question. +- **Grilling** (HITL): Conversation. The default case. Always call the Skill tool twice, for "grilling" and "domain-modeling". +- **Task** (HITL or AFK): Manual work that must happen before a _decision_ can be made: nothing to decide, prototype, or research, but the discussion is blocked until it's done. Signing up for a service so its API can be judged, provisioning access, moving data so its shape can be seen. This is the one type that _does_ rather than decides, and it earns its place by unblocking a decision, not by delivering the destination. The agent drives it alone where it can (AFK); otherwise it hands the human a precise checklist (HITL). Resolved when the work is done; the answer records what was done and any resulting facts (credentials location, new URLs, row counts) later tickets depend on. + +## Fog of war + +The map is _deliberately_ incomplete: don't chart what you can't yet see. Beyond the live tickets lies the **fog of war**: the dim view of decisions and investigations you can tell are coming but can't yet pin down, because they hang on questions still open. Resolving a ticket clears the fog ahead of it, graduating whatever's now specifiable into fresh tickets, one at a time, until the way to the destination is clear and no tickets remain. + +The map's **Not yet specified** section is where that dim view is written down: the suspected question, the area to revisit later. It's the undiscovered frontier _toward_ the destination: everything here is in scope, just not sharp enough to ticket. Write as loosely or as fully as the view allows; it doubles as a signpost for collaborators reading where the effort is headed. + +**Fog or ticket?** The test is whether you can state the question precisely now, _not_ whether you can answer it now. + +- **Ticket when** the question is already sharp, even if it's blocked and you can't act on it yet. +- **Not yet specified when** you can't yet phrase it that sharply. Don't pre-slice the fog into ticket-sized pieces: it's coarser than a ticket, and one patch may graduate into several tickets, or none, once the frontier reaches it. + +**Not yet specified** excludes what's already decided (Decisions so far), what's already a live ticket, and what's out of scope (the next section). + +## Out of scope + +Fog only ever gathers _toward_ the destination. The destination fixes the scope, so work beyond it is **out of scope**: it isn't fog, and it doesn't belong in **Not yet specified**. It gets its own **Out of scope** section on the map: work you've consciously ruled out of _this_ effort. Scope, not sharpness, lands it here. + +Out-of-scope work never graduates (the frontier stops at the destination), so it returns only if the destination is redrawn, and then as a fresh effort, not a resumption. + +Ruling something out of scope is a scoping act, not a step on the route. When a ticket that already exists turns out to sit past the destination (mis-scoped in while charting, or exposed by a resolution), **close it** (a closed ticket is unambiguously off the frontier) and leave one line in the **Out of scope** section: the gist plus why it's out of scope, linking the closed ticket. It stays out of **Decisions so far**, which records the route actually walked; a scope boundary isn't a step on it. + +## Invocation + +Two modes. Either way, **never resolve more than one ticket per session**, with the exception of research tickets. + +### Chart the map + +User invokes with a loose idea. + +1. **Name the destination.** Call the Skill tool twice, for "grilling" and "domain-modeling", to pin down what this map is finding its way to: the spec, decision, or change. The destination fixes the scope, so it's settled first. +2. **Map the frontier.** Grill again, **breadth-first** this time: fan out across the whole space rather than deep on any one thread, surfacing the open decisions and the first steps takeable now. **If this surfaces no fog** (the way to the destination is already clear, the whole journey small enough for one session), you don't need a map. Stop and ask the user how they'd like to proceed. +3. **Create the map** (label `wayfinder:map`): Destination and Notes filled in, Decisions-so-far empty, the fog sketched into **Not yet specified**. +4. **Create the tickets you can specify now** as child issues of the map, then wire blocking edges in a **second pass** (issues need ids before they can reference each other). Wiring sorts them into the frontier and the blocked; everything you can't yet specify stays in the fog: the **Not yet specified** section. +5. **Fire the research subagents.** For each `research` ticket you just created, spin up a subagent that calls the Skill tool with "research" to resolve it in parallel, capturing its findings on a throwaway `research/` branch with a context pointer from the ticket. +6. Stop: charting is one session's work; it hand-resolves nothing. + +### Work through the map + +User invokes with a map (URL or number). A ticket is **optional**: without one, you pick the next decision, not the user. + +1. Load the **map**: the low-res view, not every ticket body. +2. Choose the ticket. If the user named one, use it. Otherwise take the first frontier ticket in order. **Claim it**: assign it to yourself before any work. +3. Resolve it. **Zoom as needed**: fetch the full body of any related or closed ticket on demand; call the Skill tool for whichever skills the `## Notes` block names. If in doubt, call the Skill tool twice, for "grilling" and "domain-modeling". +4. Record the resolution: post the answer as a **resolution comment**, **close** the issue, and **append a context pointer** to the map's Decisions-so-far. +5. Add newly-surfaced tickets (create-then-wire); graduate any fog the answer has made specifiable, clearing each graduated patch from **Not yet specified** so it lives only as its new ticket. If the answer reveals that a ticket (this one or another) sits beyond the destination, **rule it out of scope** rather than resolving it on the route. If the decision invalidates other parts of the map, update or delete those tickets. + +The user may run unblocked tickets in parallel, so expect other sessions to be editing the tracker concurrently. + + + +Supporting files for this skill were downloaded to: +/tmp/skills-use-NJrHuP/wayfinder + +When the SKILL.md references relative paths, read them from that directory. diff --git a/second-brain/source-material/ui-sources.md b/second-brain/source-material/ui-sources.md new file mode 100644 index 0000000..d6c34a5 --- /dev/null +++ b/second-brain/source-material/ui-sources.md @@ -0,0 +1,30 @@ +# UI source assessment + +_Researched 2026-08-21. This is a source register, not permission to add arbitrary components._ + +## Primary component source + +Watermelon UI is the first source for application components, layouts, interaction patterns, and motion. Its public registry describes 260+ copy-paste React components for Tailwind, Radix UI, and Motion, including dashboard blocks, tables, charts, dialogs, navigation, forms, and feedback components. + +- [Watermelon UI registry](https://github.com/WatermelonCorp/watermellon-registry) +- [Watermelon UI platform](https://github.com/WatermelonCorp/watermelon-platform) + +Watermelon examples may import Lucide internally. Stackable must replace those icon imports with Iconoir equivalents. Do not introduce Lucide. + +## Discovery sources + +- [Shoogle](https://shoogle.dev/) is a discovery directory rather than a component system. Use it to find source components only when Watermelon lacks the needed primitive. +- ReactBits and Aceternity UI remain named fallback sources in the initial brief. Verify component quality, license, accessibility, and dependency fit before use. +- Canvas UI appeared in Shoogle results. Its heavy canvas/WebGL effects are a poor default for an operational CI dashboard. Use only if a specific, accessible interaction needs it. + +## Design and motion review sources + +- [Emil Kowalski's skills](https://github.com/emilkowalski/skills) now has a preserved local copy at [[skills/emil-design-eng.txt]]. Apply its motion rules: animation must clarify state or feedback, use transform/opacity, remain short, respect reduced motion, and never slow high-frequency operations. +- Cursor's [[skills/unslop.txt]] applies to user-facing copy. Keep copy concrete, plain, and free of generic AI phrasing. + +## Current visual constraints + +- Purple, onyx, silver, and black. +- Geist and Satoshi. +- Iconoir only for icons. +- No decorative AI-generated SVGs. A deterministic SVG rendered from current state is required for the live PR status visualization. diff --git a/second-brain/wayfinder/stackable-product-map.md b/second-brain/wayfinder/stackable-product-map.md new file mode 100644 index 0000000..7ca3d42 --- /dev/null +++ b/second-brain/wayfinder/stackable-product-map.md @@ -0,0 +1,31 @@ +# Stackable Product Wayfinder Map + +## Destination + +A validated, implementation-ready MVP specification for Stackable: a GitHub-native CI maintainability web platform and CLI, including its initial workflow, integration boundaries, data model direction, and interaction/design principles. + +## Notes + +- This is a planning map, not an implementation plan. +- Follow the one-question interview cadence while key ambiguities remain. +- Consult the preserved grill-me, wayfinder, find-skills, and interview-me instructions each session. +- Use the product brief's component, typography, palette, keyboard-image, and Iconoir constraints when prototypes begin. + +## Decisions so far + +- [[product/decision-log]]: Stackable is positioned around CI maintainability rather than managed runner infrastructure. +- [[product/decision-log]]: v1 covers the three connected pillars together—PR health, AI CI/CD authoring, and organization management—on GitHub.com. +- [[product/decision-log]]: v1 also includes CircleCI and Buildkite adapters, deterministic live PR-status SVGs, GitHub App/OAuth/CLI/MCP identity, scoped direct writes, and Inngest-driven asynchronous work. + +## Frontier + +- **Grilling — define operational data boundary and deployment target.** GitHub.com, the GitHub App, OAuth, and CLI device/token identity are selected; determine what CI/log data Stackable stores, for how long, and where. +- **Grilling — define the v1 cross-pillar contract.** PR health, AI CI/CD authoring, and organization views will all ship in v1; determine the smallest dependable depth for each. + +## Not yet specified + +- Source-control platform scope, GitHub App permission model, organization tenancy, reporting contract, PR-comment update semantics, AI safety/review workflow, CLI command design, architecture, data retention, pricing, and launch positioning. + +## Out of scope + +- Building a managed CI runner fleet in the initial Stackable product map.