From 27c60a1d23eafb1ea49c79e76d6e36526cb7dc53 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 22 Jan 2026 22:39:22 +0000 Subject: [PATCH 1/2] chore: sync BaseProject skills, docs, and agent config - Added 8 new Claude Code skills (grove-documentation, grove-spec-writing, grove-testing, grove-ui-design, heartwood-auth, museum-documentation, npm-publish, walking-through-the-grove) - Updated AGENT.md with new sections: Pull Requests, Authentication, Grove-related skills - Updated TODO Management to mention COMPLETED.md - Synced all existing skills from BaseProject - AgentUsage/ documentation already up to date - .gitignore already contains all BaseProject entries --- .claude/skills/grove-documentation/SKILL.md | 477 +++++++++ .claude/skills/grove-spec-writing/SKILL.md | 450 ++++++++ .claude/skills/grove-testing/SKILL.md | 437 ++++++++ .claude/skills/grove-ui-design/SKILL.md | 989 ++++++++++++++++++ .claude/skills/heartwood-auth/SKILL.md | 307 ++++++ .claude/skills/museum-documentation/SKILL.md | 502 +++++++++ .claude/skills/npm-publish/SKILL.md | 195 ++++ .../skills/walking-through-the-grove/SKILL.md | 248 +++++ AGENT.md | 65 +- 9 files changed, 3668 insertions(+), 2 deletions(-) create mode 100644 .claude/skills/grove-documentation/SKILL.md create mode 100644 .claude/skills/grove-spec-writing/SKILL.md create mode 100644 .claude/skills/grove-testing/SKILL.md create mode 100644 .claude/skills/grove-ui-design/SKILL.md create mode 100644 .claude/skills/heartwood-auth/SKILL.md create mode 100644 .claude/skills/museum-documentation/SKILL.md create mode 100644 .claude/skills/npm-publish/SKILL.md create mode 100644 .claude/skills/walking-through-the-grove/SKILL.md diff --git a/.claude/skills/grove-documentation/SKILL.md b/.claude/skills/grove-documentation/SKILL.md new file mode 100644 index 0000000..a0cbfc1 --- /dev/null +++ b/.claude/skills/grove-documentation/SKILL.md @@ -0,0 +1,477 @@ +--- +name: grove-documentation +description: Write documentation, help articles, specs, and user-facing text in the authentic Grove voice. Use when writing any text that users will read, updating help center content, or drafting specs. Ensures warmth, clarity, and avoidance of AI patterns. +--- + +# Grove Documentation Skill + +## When to Activate + +Activate this skill when: +- Writing help center articles (Waystone) +- Drafting specs or technical documentation +- Writing user-facing text (onboarding, tooltips, error messages) +- Creating landing page copy +- Writing blog posts for the Grove platform itself +- Reviewing existing docs for voice consistency +- Any time you're writing words that users will read + +--- + +## The Grove Voice + +From the project's guiding principles: + +> This site is my authentic voiceโ€”warm, introspective, queer, unapologetically building something meaningful; write like you're helping me speak, not perform. + +> Write with the warmth of a midnight tea shop and the clarity of good documentationโ€”this is my space, make it feel like home. + +### What Grove Sounds Like + +**Warm but not cutesy.** We're friendly, not performative. "Let's get started" feels right. "Let's gooo! ๐Ÿš€" does not. + +**Direct and honest.** Say what you mean. Acknowledge limitations. Don't oversell. If something doesn't work yet, say so. + +**Conversational but not sloppy.** Contractions are fine (you're, it's, we're). Short paragraphs. Questions that invite readers in. But still clear, still structured. + +**Introspective.** Grove makes space for reflection. We don't rush. We ask "why" alongside "how." + +**Poetic in small doses.** Italicized one-liners at the end of sections can land beautifully. Use them sparingly, earn them. + +### Sentence Rhythm + +Mix short sentences with longer ones. Vary your rhythm. Read it aloudโ€”if it sounds monotonous, it is. + +**Good:** +> Every new visitor asks the same question. "Is the music broken?" No. There is no music. There never has been. + +**Not good:** +> Every new visitor asks a common question. The question is usually about whether the music system is functioning. The answer is that there is no music system. There has never been one. + +--- + +## User Identity Terminology + +Grove uses specific terms for community members. **Always use these in user-facing text.** + +| Term | Who | Context | +|------|-----|---------| +| **Wanderer** | Everyone | Default greeting, anonymous visitors, all users | +| **Rooted** / **the Rooted** | Subscribers | Those who've planted their tree, paid users | +| **Pathfinder** | Trusted guides | Appointed community helpers | +| **Wayfinder** | Autumn (singular) | The grove keeper | + +### Key Rules + +- **Never use "user" or "member"** in user-facing text. Use "Wanderer" instead. +- **Never use "subscriber"** in user-facing text. Use "Rooted" or "the Rooted". +- **Personal emails** (day-1, day-3, etc.) should use `{{name}}`, not "Wanderer". +- **Generic greetings** (welcome pages, UI) should use "Wanderer". + +### Examples + +**Good:** +- "Welcome, Wanderer." +- "Thanks for staying rooted with us." +- "Ask a Pathfinder. They'll show you the way." + +**Avoid:** +- "Welcome, user." +- "Thanks for being a subscriber." +- "Contact an administrator." + +### The Symmetry + +Wanderer โ†’ Wayfinder reflects the journey: +- Wanderers *seek* the way (exploring, finding paths) +- The Wayfinder *shows* the way (guiding, creating paths) + +See `docs/grove-user-identity.md` for full documentation. + +--- + +## Strict Avoidances + +These patterns make text sound like AI wrote it. Avoid them completely. + +### Em-Dashes + +**Avoid em-dashes (โ€”).** One tasteful use per thousand words, maximum. Use commas, periods, or parentheses instead. + +**Avoid:** The forestโ€”our homeโ€”is where we gather. +**Better:** The forest is our home. It's where we gather. +**Also fine:** The forest (our home) is where we gather. + +### The "Not X, But Y" Pattern + +This phrasing is deeply AI-coded. Avoid it entirely. + +**Never write:** +- "It's not X, but Y" +- "It's not just X, but Y" +- "It's not merely X, but rather Y" +- "Grove isn't just a platform, it's a home" + +**Instead, just say the thing:** +- "Grove is a home for your words." +- "This is where you belong." + +### Overused AI Words + +These words appear in AI text at rates far higher than human writing. Avoid them: + +| Category | Words to Avoid | +|----------|---------------| +| **Adjectives** | robust, seamless, innovative, cutting-edge, transformative, intricate, captivating, comprehensive | +| **Nouns** | tapestry, camaraderie, realm, plethora, myriad, landscape, journey (when not literal) | +| **Verbs** | delve, foster, leverage, navigate, empower, embark, unlock, harness | +| **Phrases** | at the end of the day, in today's world, it goes without saying, needless to say | + +### Heavy Transition Words + +These make text feel stiff and robotic: + +- Furthermore +- Moreover +- Additionally +- In conclusion +- That being said +- It's worth noting that +- It's important to note + +**Instead:** Let ideas connect naturally. Use short transitions like "And," "But," "So," "Still." Or no transition at allโ€”just start the next thought. + +### Semantic Echoes + +Don't repeat the same adjective or descriptor multiple times. AI does this constantly. + +**Bad:** +> Grove provides a seamless experience. The seamless integration means you can seamlessly move between features. + +**Good:** +> Grove gets out of your way. Move between features without friction. + +### Generic Safe Claims + +AI hedges. Humans commit. + +**Bad:** "This may help improve your workflow in many cases." +**Good:** "This makes your workflow faster." + +--- + +## Structural Guidelines + +### Paragraphs + +Keep them short. One idea per paragraph. Two to four sentences is usually right. + +White space is your friend. Dense walls of text don't feel like home. + +### Lists + +Use lists when they clarify. But don't turn everything into bullets. Sometimes prose flows better. + +**Good use of lists:** +- Specific steps in a process +- Features that are truly parallel +- Quick reference information + +**Bad use of lists:** +- Narrative content broken awkwardly +- Things that would read better as a sentence + +### Headers + +Be specific. "Writing Guidelines" is better than "Guidelines." "What Grove Sounds Like" is better than "Voice." + +Action-oriented headers work well for help docs: "Add Your First Post" not "Posts." + +### Callouts + +Use sparingly. When you do: + +> ๐Ÿ’ก **Tip:** Helpful suggestion that enhances understanding. + +> โš ๏ธ **Warning:** Something that could cause problems if ignored. + +Don't use callouts for things that should just be in the text. + +--- + +## Closers + +Grove docs often end with an italicized line. This should feel earned, not forced. + +**Works:** +> *Sometimes the most radical thing you can offer is nothing at all.* + +> *The path becomes clear by walking it.* + +**Doesn't work:** +> *And that's how you configure your settings!* + +If you can't find a poetic closer that resonates, don't force one. A clean ending is fine. + +--- + +## Queer-Friendly Language + +Grove is explicitly queer-friendly. This means: + +- No assumptions about users' identities or relationships +- Welcoming, inclusive language throughout +- Safe space messaging where appropriate +- Pride in what we're building, not defensiveness + +### Concrete Examples + +| Avoid | Use Instead | +|-------|-------------| +| "Add your husband/wife" | "Add your partner" or "Add someone special" | +| "he or she" | "they" or rephrase to avoid pronouns | +| "Dear Sir/Madam" | "Hello" or "Hi there" | +| "mankind" | "people" or "everyone" | +| Examples with only straight couples | Vary your examples, or keep them neutral | + +### In User Flows + +When asking for relationship info (if ever needed): +- Use open text fields over dropdowns with limited options +- Don't require titles (Mr/Mrs/Ms) +- Let people describe themselves rather than selecting from boxes + +### Tone + +We don't make a big deal of being queer-friendly. We just are. No rainbow-washing, no performative allyship. The inclusivity is baked in, not bolted on. + +--- + +## Technical Docs vs. User Docs + +**Specs and internal docs** can be more matter-of-fact. Tables, schemas, API referencesโ€”these need clarity over warmth. + +**User-facing docs** (help center, onboarding, error messages) carry the full Grove voice. + +Both should avoid AI patterns. + +### The Voice Spectrum + +**API Reference (minimal warmth, maximum clarity):** +``` +POST /api/posts + +Creates a new blog post. + +Parameters: +- title (string, required): Post title +- content (string, required): Markdown content +- published (boolean): Default false + +Returns: Post object or 400 error +``` + +**Internal Spec (clear, some personality):** +``` +## Feed Caching Strategy + +Feed pages cache for 5 minutes in KV. When a new post is shared, +we invalidate the chronological feed but let popular/hot feeds +age out naturally. This keeps things fresh without hammering D1. +``` + +**Getting Started Guide (full Grove voice):** +``` +## Your First Post + +Welcome. Let's get something published. + +The editor opens to a blank page. That's intentional. No templates, +no suggested topics. Just you and your words. + +Write something. Anything. Hit publish when it feels ready. +``` + +**Onboarding Tooltip (warm but concise):** +``` +This is your dashboard. Everything you need, nothing you don't. +``` + +--- + +## Error Messages + +When things break, stay warm but be honest. Don't blame the user. Don't hide behind vague language. + +### Error Message Principles + +1. **Say what happened** (briefly) +2. **Say what they can do** (if anything) +3. **Don't over-apologize** (one "sorry" max) +4. **Don't be cute when things are broken** + +### Examples + +**Good:** +``` +Couldn't save your post. Check your connection and try again. +``` + +``` +That page doesn't exist. It may have been moved or deleted. +``` + +``` +Something went wrong on our end. We're looking into it. +Your draft is saved locally. +``` + +**Avoid:** +``` +Oops! ๐Ÿ˜… Looks like something went wrong! Don't worry though, +these things happen! Please try again later! +``` + +``` +Error 500: Internal Server Error. Contact administrator. +``` + +``` +We're SO sorry!!! We feel TERRIBLE about this!!! +Please forgive us and try again! +``` + +### The Balance + +Be honest about what broke. Be helpful about next steps. Don't make them feel stupid. Don't make yourself sound incompetent. One sentence is usually enough. + +--- + +## Self-Review Checklist + +Before finalizing any Grove documentation: + +- [ ] Read it aloud. Does it sound human? +- [ ] Check for em-dashes. Remove them. +- [ ] Search for "not just" and "but rather." Rewrite. +- [ ] Look for words from the avoid list. Replace them. +- [ ] Vary sentence length. No monotone rhythm. +- [ ] Cut unnecessary transitions. Ideas should flow naturally. +- [ ] Is the closer earned? If forced, remove it. +- [ ] Would you want to read this at 2 AM in a tea shop? + +--- + +## Integration with Other Skills + +When **grove-ui-design** or **walking-through-the-grove** need written content, invoke this skill first. The visual design and naming should match the voice. + +**Typical flow:** +1. Design calls for new component/page text +2. Activate `grove-documentation` for voice guidance +3. Write the content following these principles +4. Return to design/naming work + +### When to Use museum-documentation Instead + +This skill (grove-documentation) is for **quick, functional text**: help articles, error messages, tooltips, onboarding copy. Content that's read in passing. + +Use **museum-documentation** when you need **narrative, explorable documentation**: + +| Use grove-documentation | Use museum-documentation | +|------------------------|-------------------------| +| Help center articles | Knowledge base "how it works" | +| Tooltips and labels | Codebase guided tours | +| Error messages | System architecture explains | +| Onboarding flows | Technical deep-dives for curious Wanderers | +| Quick-reference guides | Exhibit-style documentation | + +If the reader should **skim and act**, use this skill. +If the reader should **explore and understand**, use museum-documentation. + +--- + +## Examples + +### Help Center Article (Good) + +```markdown +# Your First Post + +Welcome. Let's get something published. + +From your admin panel, click **New Post** in the sidebar. The editor opens with a blank canvas. + +Write in Markdown. If you're new to it, here are the basics: +- **Bold:** `**text**` +- *Italic:* `*text*` +- Links: `[text](url)` + +The preview panel shows how your post will look. Toggle it with the eye icon. + +When you're ready, hit **Publish**. Your words are live. + +*The blank page isn't as scary as it looks.* +``` + +### Help Center Article (Bad - Obvious AI Patterns) + +```markdown +# Your First Post + +Furthermore, in today's digital landscape, creating your first blog post is an exciting journey! It's not just about writingโ€”it's about expressing yourself in a transformative way. + +Navigate to your admin panel and leverage the New Post functionality. The seamless editor provides a robust interface for your content creation needs. + +Additionally, Grove utilizes Markdownโ€”a comprehensive formatting system that empowers you to create intricate, captivating content. Moreover, the preview feature allows you to visualize your post before publication. + +Embark on your blogging journey today! +``` + +### Help Center Article (Bad - Subtle AI Patterns) + +This one's trickier. It looks okay at first glance: + +```markdown +# Your First Post + +Ready to share your thoughts with the world? Let's get started. + +From your admin panel, click **New Post** in the sidebar. You'll see our editorโ€”a clean, distraction-free space for your writing. + +Grove uses Markdown for formatting. It's not complicatedโ€”here are the basics you'll need: +- **Bold:** `**text**` +- *Italic:* `*text*` +- Links: `[text](url)` + +The preview panel lets you see how your post will look before publishing. When you're satisfied with your work, hit **Publish**. + +Your voice matters. We can't wait to see what you create. +``` + +**What's wrong:** +- "Ready to share your thoughts with the world?" (generic opener) +- "Let's get started" (overused) +- "distraction-free space" (marketing-speak) +- "It's not complicated" (defensive hedge, "not X" pattern adjacent) +- "When you're satisfied with your work" (formal) +- "Your voice matters. We can't wait to see what you create." (hollow encouragement) + +--- + +## Quick Reference + +| Do | Don't | +|----|-------| +| Write short paragraphs | Write walls of text | +| Use "and," "but," "so" | Use "Furthermore," "Moreover" | +| Say what you mean | Hedge with "may," "might," "could" | +| Vary sentence rhythm | Write uniform sentence lengths | +| Use commas or periods | Use em-dashes | +| Let ideas connect naturally | Force transitions everywhere | +| Earn poetic closers | Force poetic closers | +| Acknowledge limitations | Oversell or overpromise | + +--- + +*Write like you're explaining something to a friend at 2 AM. Clear, warm, honest.* diff --git a/.claude/skills/grove-spec-writing/SKILL.md b/.claude/skills/grove-spec-writing/SKILL.md new file mode 100644 index 0000000..035182b --- /dev/null +++ b/.claude/skills/grove-spec-writing/SKILL.md @@ -0,0 +1,450 @@ +--- +name: grove-spec-writing +description: Write and validate Grove technical specifications with consistent formatting, ASCII art headers, diagrams, and the Grove voice. Use when creating new specs, reviewing existing specs for completeness, or standardizing spec formatting. +--- + +# Grove Spec Writing + +A comprehensive guide for writing technical specifications in the Grove ecosystem. Use this skill to create new specs that feel like storybook entries, or to validate and standardize existing specs. + +## When to Activate + +- Creating a new technical specification +- Reviewing an existing spec for completeness +- Adding ASCII art headers to specs missing them +- Adding diagrams, mockups, or visual elements to text-heavy specs +- Standardizing frontmatter across spec files +- Validating a spec against Grove standards before finalizing + +--- + +## The Spec as Storybook Entry + +Grove specs aren't just technical documents. They're **storybook entries** in a larger narrative. Each spec should feel like opening a page in a beautifully illustrated field guide to the forest. + +**The formula:** +1. **Cover page** (frontmatter + ASCII art + tagline) +2. **Introduction** (what is this, in nature and in Grove) +3. **The journey** (architecture, flows, implementation) +4. **The details** (API, schema, security) +5. **The path forward** (implementation checklist) + +--- + +## Required Structure + +### 1. Frontmatter (REQUIRED) + +Every spec MUST have this exact frontmatter format: + +```yaml +--- +aliases: [] +date created: [Day], [Month] [Ordinal] [Year] +date modified: [Day], [Month] [Ordinal] [Year] +tags: + - primary-domain + - tech-stack + - category +type: tech-spec +--- +``` + +**Date format examples:** +- `Monday, December 29th 2025` +- `Saturday, January 4th 2026` + +**Type options:** +- `tech-spec` โ€” Technical specification (most common) +- `implementation-plan` โ€” Step-by-step implementation guide +- `index` โ€” Index/navigation document + +### 2. ASCII Art Header (REQUIRED) + +Immediately after frontmatter, include a code block with ASCII art that visually represents the concept: + +``` +# [Name] โ€” [Short Description] + +``` + ASCII ART HERE + representing the concept + in a visual way +``` + +> *Poetic tagline in italics* +``` + +**Good ASCII art:** +- Relates to the nature metaphor (forest, garden, etc.) +- Represents the concept visually (layers for backup, rings for analytics) +- Uses box-drawing characters: `โ”€โ”‚โ”Œโ”โ””โ”˜โ”œโ”คโ”ฌโ”ดโ”ผโ•ญโ•ฎโ•ฐโ•ฏ` +- Uses nature emoji sparingly: `๐ŸŒฒ๐ŸŒฟ๐Ÿ‚โœจ๐ŸŒธ` +- Includes a poetic tagline or motto + +**Examples from excellent specs:** + +**Wisp (will-o'-the-wisp light):** +``` + ๐ŸŒฒ ๐ŸŒฒ ๐ŸŒฒ + \ | / + \ | / + โœจ + โ•ฑ โ•ฒ + โ•ฑ โ•ฒ + โ•ฑ ยท โ•ฒ + โ•ฑ ยท โ•ฒ + โ•ฑ ยท โ•ฒ + ยท ยท ยท + gentle + guiding + light +``` + +**Patina (layered backups):** +``` + โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ + โ•ญโ”ค โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”œโ•ฎ + โ•ญโ”คโ”‚ โ”‚ 2026-01-05 โ”‚ โ”‚โ”œโ•ฎ + โ”‚โ”‚โ”‚ โ”‚ โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“ โ”‚ โ”‚โ”‚โ”‚ + โ”‚โ”‚โ”‚ โ”‚ โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’ โ”‚ โ”‚โ”‚โ”‚ + โ”‚โ”‚โ”‚ โ”‚ โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘ โ”‚ โ”‚โ”‚โ”‚ + โ”‚โ”‚โ”‚ โ”‚ ยทยทยทยทยทยทยทยทยทยท โ”‚ โ”‚โ”‚โ”‚ + โ•ฐโ”ดโ”ดโ”€โ”€โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜โ”€โ”€โ”ดโ”ดโ•ฏ + โ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑโ•ฑ + โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + ~~~~~~~~ oxidation layer ~~~~~~~~ + Age as armor. Time as protection. +``` + +**Heartwood (tree rings):** +``` + โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ + โ•ญโ”€โ”€โ”‚ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ”‚โ”€โ”€โ•ฎ + โ•ญโ”€โ”‚ โ”‚ โ”‚ โ•ญโ”€โ”€โ•ฎ โ”‚ โ”‚ โ”‚โ”€โ•ฎ + โ”‚ โ”‚ โ”‚ โ”‚ โ”‚โ™ฅ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ + โ•ฐโ”€โ”‚ โ”‚ โ”‚ โ•ฐโ”€โ”€โ•ฏ โ”‚ โ”‚ โ”‚โ”€โ•ฏ + โ•ฐโ”€โ”€โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ”‚โ”€โ”€โ•ฏ + โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + + every ring: a year, a story, a layer of growth + + The center that holds it all. +``` + +### 3. Introduction Section + +After the ASCII art header: + +```markdown +> *Poetic tagline repeated* + +[2-3 sentence description of what this is in the Grove ecosystem] + +**Public Name:** [Name] +**Internal Name:** Grove[Name] +**Domain:** `name.grove.place` +**Repository:** [Link if applicable] +**Last Updated:** [Month Year] + +[1-2 paragraphs explaining the nature metaphor and how it applies] + +--- +``` + +### 4. Body Sections + +Organize content with clear headers. Include: + +- **Overview/Goals** โ€” What this system does +- **Architecture** โ€” How it's built (with diagrams!) +- **Tech Stack** โ€” Dependencies, frameworks +- **API/Schema** โ€” Technical details +- **Security** โ€” Important considerations +- **Implementation Checklist** โ€” Clear action items + +--- + +## Required Visual Elements + +### Flow Diagrams + +Every spec describing a process MUST include at least one ASCII flow diagram: + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Client Sites โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ Site A โ”‚ โ”‚ Site B โ”‚ โ”‚ Site C โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ + โ”‚ โ”‚ โ”‚ + โ”‚ 1. Request โ”‚ โ”‚ + โ–ผ โ–ผ โ–ผ +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ Central Service โ”‚ +โ”‚ โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ Handler A โ”‚ โ”‚ Handler B โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +**Box drawing reference:** +- Corners: `โ”Œ โ” โ”” โ”˜` (square) or `โ•ญ โ•ฎ โ•ฐ โ•ฏ` (rounded) +- Lines: `โ”€ โ”‚ โ• โ•‘` +- Joins: `โ”œ โ”ค โ”ฌ โ”ด โ”ผ` +- Arrows: `โ†’ โ† โ†‘ โ†“ โ–ถ โ—€ โ–ฒ โ–ผ` + +### UI Mockups + +Specs describing user interfaces MUST include ASCII mockups: + +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” +โ”‚ โœง Panel Title [ร—] โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค +โ”‚ โ”‚ +โ”‚ โ”Œโ”€ Label โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ Content here with proper spacing โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ”‚ โ”‚ +โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ +โ”‚ โ”‚ Input field... [โ†ต] โ”‚ โ”‚ +โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ +โ”‚ โ”‚ +โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚ +โ”‚ [ Action A ] [ Action B โœฆ ] โ”‚ +โ”‚ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +### State Diagrams + +For features with multiple states: + +``` + Idle: Analyzing: Success: + . * . . * . * . analyzing . * * + . _ . . \ | / . * /|\ . + / \ * . -- (o.o) -- thinking * / | \ * + / ~ ~ \ . . / | \ /__|__\ + / \______ ~~~~~~~~~~~~~~~~~ ~~~~/ \~~~~ + ~~~~~~~~~~~~~~~~~~~ words flowing... all clear +``` + +### Comparison Tables + +Use tables to compare options, states, or configurations: + +```markdown +| Feature | Seedling | Sapling | Oak | Evergreen | +|---------|----------|---------|-----|-----------| +| Posts | 50 | 250 | โˆž | โˆž | +| Storage | 1 GB | 5 GB | 20 GB | 100 GB | +| Themes | 3 | 10 | All | All + custom | +``` + +### Timeline/Retention Diagrams + +For anything involving time: + +``` + TODAY 12 WEEKS AGO + โ”‚ โ”‚ + โ–ผ โ–ผ + โ”Œโ”€โ”ฌโ”€โ”ฌโ”€โ”ฌโ”€โ”ฌโ”€โ”ฌโ”€โ”ฌโ”€โ” โ”Œโ”€โ” + โ”‚โ–ˆโ”‚โ–ˆโ”‚โ–ˆโ”‚โ–ˆโ”‚โ–ˆโ”‚โ–ˆโ”‚โ–ˆโ”‚ โ—€โ”€โ”€ Daily backups (7 days) โ”‚โ–‘โ”‚ + โ””โ”€โ”ดโ”€โ”ดโ”€โ”ดโ”€โ”ดโ”€โ”ดโ”€โ”ดโ”€โ”˜ โ””โ”€โ”˜ + S M T W T F S +``` + +--- + +## Validation Checklist + +Before finalizing any spec, verify: + +### Structure +- [ ] Frontmatter present with all required fields +- [ ] `aliases: []` included (even if empty) +- [ ] Date format correct (Day, Month Ordinal Year) +- [ ] `type: tech-spec` or appropriate type +- [ ] ASCII art header present after frontmatter +- [ ] Poetic tagline in italics +- [ ] Public/Internal names listed +- [ ] Domain specified (if applicable) + +### Visual Content +- [ ] At least one ASCII flow diagram (if process-based) +- [ ] UI mockups included (if describing interface) +- [ ] Tables for comparisons where appropriate +- [ ] Code blocks for technical details +- [ ] No walls of text without visual breaks + +### Voice (refer to grove-documentation skill) +- [ ] No em-dashes (use periods or commas) +- [ ] No "not X, but Y" patterns +- [ ] No AI-coded words (robust, seamless, leverage, etc.) +- [ ] Short paragraphs +- [ ] Poetic closers earned, not forced + +### Completeness +- [ ] Overview/Goals section +- [ ] Architecture diagram +- [ ] Technical details (API, schema) +- [ ] Security considerations +- [ ] Implementation checklist + +--- + +## Creating ASCII Art + +### The Process + +1. **Identify the core metaphor** โ€” What natural thing does this represent? +2. **Sketch the concept** โ€” What visual would convey this at a glance? +3. **Choose your characters** โ€” Box drawing, emoji, or creative ASCII +4. **Build in layers** โ€” Start with outline, add detail, add flourishes +5. **Add the tagline** โ€” Poetic one-liner that captures the essence + +### Character Palette + +**Box Drawing (safe, consistent):** +``` +โ”Œโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ” โ•ญโ”€โ”€โ”€โ”€โ”€โ•ฎ +โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ +โ”œโ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”ค โ•ฐโ”€โ”€โ”€โ”€โ”€โ•ฏ +โ”‚ โ”‚ โ”‚ +โ””โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”˜ +``` + +**Lines and Arrows:** +``` +โ†’ โ† โ†‘ โ†“ โ†” โ†• +โ–ถ โ—€ โ–ฒ โ–ผ +โŸฟ โŸธ โŸน +``` + +**Nature Emoji (use sparingly):** +``` +๐ŸŒฒ ๐ŸŒณ ๐ŸŒฟ ๐Ÿ‚ ๐Ÿƒ ๐ŸŒธ ๐ŸŒบ ๐ŸŒป ๐ŸŒท ๐ŸŒฑ ๐Ÿ„ +โ˜€๏ธ ๐ŸŒค๏ธ โญ โœจ ๐Ÿ’ง ๐Ÿ”ฅ +๐Ÿฆ‹ ๐Ÿ› ๐ŸŒ +``` + +**Decorative:** +``` +ยท โˆ™ โ€ข ยฐ หš โˆ˜ +~ โ‰ˆ โˆฟ +โ• โ•‘ โ•” โ•— โ•š โ• +โ–‘ โ–’ โ–“ โ–ˆ +``` + +### Tips + +- Keep ASCII art under 20 lines tall +- Center the art within its code block +- Include breathing room (empty lines above/below) +- Test in a monospace font +- Consider mobile rendering (simpler is better) + +--- + +## Example: Complete Spec Header + +```markdown +--- +aliases: [] +date created: Monday, January 6th 2026 +date modified: Monday, January 13th 2026 +tags: + - support + - user-communication + - cloudflare-workers +type: tech-spec +--- + +# Porch โ€” Support System + +``` + ๐Ÿ  + ___โ”‚___ + โ”‚ โ”‚ + ~~~~~~โ”‚ PORCH โ”‚~~~~~~ + โ•ฑโ”‚_______โ”‚โ•ฒ + โ•ฑ โ•ฒ + โ•ฑ โ”Œโ”€โ”€โ”€โ” โ•ฒ + โ•ฑ โ”‚ โ˜• โ”‚ โ•ฒ + โ•ฑ โ””โ”€โ”€โ”€โ”˜ ๐Ÿ‘ค โ•ฒ + โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + steps + + Have a seat. We'll figure it out. +``` + +> *Have a seat on the porch. We'll figure it out together.* + +Grove's front porch: a warm, accessible space where users sit down and have a conversation. Not a corporate help desk with ticket numbers. A porch where you chat with the grove keeper about what's going on. + +**Public Name:** Porch +**Internal Name:** GrovePorch +**Domain:** `porch.grove.place` +**Status:** Planned (Launch Priority) + +A porch is where you sit and talk. You come up the steps, have a seat, and the grove keeper comes out to chat. It's not a ticket counter. It's two people on a porch, figuring things out together. + +--- +``` + +--- + +## Integration with Other Skills + +### Before Writing a Spec + +1. **walking-through-the-grove** โ€” If naming a new feature, complete the naming journey first +2. **grove-ui-design** โ€” If the spec involves UI, understand design patterns + +### While Writing + +3. **grove-documentation** โ€” Apply Grove voice throughout, avoid AI patterns + +### After Writing + +4. **grove-spec-writing** (this skill) โ€” Run validation checklist +5. Review with fresh eyes: Does it feel like a storybook entry? + +### When to Use museum-documentation Instead + +This skill (grove-spec-writing) is for **internal technical specifications**: architecture decisions, system design, implementation plans. Documentation for developers. + +Use **museum-documentation** when writing for **Wanderers who want to understand**: + +| Use grove-spec-writing | Use museum-documentation | +|-----------------------|-------------------------| +| Technical specifications | "How it works" for curious visitors | +| Architecture decisions | Codebase guided tours | +| Implementation plans | Knowledge base exhibits | +| Internal system docs | Narrative technical explanations | + +If the reader is a **developer implementing something**, use this skill. +If the reader is a **Wanderer exploring the forest**, use museum-documentation. + +--- + +## Quick Reference + +| Element | Required | Location | +|---------|----------|----------| +| Frontmatter | Yes | Top of file | +| ASCII art header | Yes | After frontmatter | +| Poetic tagline | Yes | After ASCII art | +| Public/Internal names | Yes | Introduction | +| Architecture diagram | If applicable | Body | +| UI mockups | If has UI | Body | +| Implementation checklist | Yes | End of spec | + +--- + +*A good spec is one you'd want to read at 2 AM. Make it beautiful.* diff --git a/.claude/skills/grove-testing/SKILL.md b/.claude/skills/grove-testing/SKILL.md new file mode 100644 index 0000000..6d83e9a --- /dev/null +++ b/.claude/skills/grove-testing/SKILL.md @@ -0,0 +1,437 @@ +--- +name: grove-testing +description: Write effective, maintainable tests that catch real bugs and enable confident refactoring. Use when deciding what to test, reviewing test quality, or writing tests for Grove features. Focuses on philosophy and strategyโ€”pair with javascript-testing for implementation details. +--- + +# Grove Testing Skill + +## When to Activate + +Activate this skill when: +- Deciding **what** to test (not just how) +- Writing tests for new Grove features +- Reviewing existing tests for effectiveness +- Asked to "add tests" without specific guidance +- Evaluating whether tests are providing real value +- Refactoring causes many tests to break (symptom of bad tests) + +**For technical implementation** (Vitest syntax, mocking patterns, assertions), use the `javascript-testing` skill alongside this one. + +--- + +## The Testing Philosophy + +> *"Write tests. Not too many. Mostly integration."* +> โ€” Guillermo Rauch + +This captures everything Grove believes about testing: + +**Write tests** โ€” Automated tests are worthwhile. They enable confident refactoring, serve as documentation, and catch regressions before users do. + +**Not too many** โ€” Tests have diminishing returns. The goal isn't coverage numbers. It's confidence. When you feel confident shipping, you have enough tests. + +**Mostly integration** โ€” Integration tests catch real problems without being brittle. They test behavior users actually experience, not internal implementation. + +### The Guiding Principle + +> *"The more your tests resemble the way your software is used, the more confidence they can give you."* +> โ€” Kent C. Dodds (Testing Library) + +Ask yourself: **Does this test fail when the feature breaks?** If yes, it's valuable. If it only fails during refactors, it's testing implementation details. + +--- + +## What Makes a Test Valuable + +A good test has these properties (Kent Beck's Test Desiderata): + +| Property | What It Means | +|----------|---------------| +| **Behavior-sensitive** | Fails when actual functionality breaks | +| **Structure-immune** | Doesn't break when you refactor safely | +| **Deterministic** | Same result every time, no flakiness | +| **Fast** | Gives feedback in seconds, not minutes | +| **Clear diagnosis** | When it fails, you know exactly what broke | +| **Cheap to write** | Effort proportional to code complexity | + +### The Confidence Test + +Before writing a test, ask: + +1. **Would I notice if this broke in production?** If yes, test it. +2. **Would this test fail if the feature broke?** If no, don't write it. +3. **Does this test resemble how users interact with the feature?** If no, reconsider. + +--- + +## What NOT to Test + +Not everything needs tests. Some things actively harm your codebase when tested. + +### Skip Testing + +| What | Why | +|------|-----| +| **Trivial code** | Getters, setters, data models with no logic | +| **Framework behavior** | Trust that SvelteKit routing works | +| **Implementation details** | Internal state, private methods, CSS classes | +| **One-off scripts** | Maintenance cost exceeds value | +| **Volatile prototypes** | Requirements unclear, code will change | + +### Test Lightly + +| What | Approach | +|------|----------| +| **Configuration** | Smoke test that it loads, not every option | +| **Third-party integrations** | Mock at boundaries, test your code's response | +| **Visual design** | Snapshot tests or visual regression, not unit tests | + +### Test Thoroughly + +| What | Why | +|------|-----| +| **Business logic** | Core value of the application | +| **User-facing flows** | What users actually experience | +| **Edge cases** | Error states, empty states, boundaries | +| **Bug fixes** | Every bug becomes a test to prevent regression | + +--- + +## The Testing Trophy + +Modern JavaScript testing follows the Testing Trophy, not the old Testing Pyramid: + +``` + โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ + โ”‚ E2E โ”‚ โ† Few: critical user journeys + โ•ฐโ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ•ฏ + โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ + โ”‚ Integration โ”‚ โ† Many: this is where confidence lives + โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ + โ”‚ Unit โ”‚ โ† Some: pure functions, algorithms + โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ + โ”‚ Static Analysis โ”‚ โ† TypeScript, ESLint (always on) + โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +``` + +### What Each Layer Does + +**Static Analysis (TypeScript, ESLint)** +- Catches typos, type errors, obvious mistakes +- Zero runtime cost, always running +- This is your first line of defense + +**Unit Tests** +- Pure functions, algorithms, utilities +- Fast, isolated, easy to debug +- Don't mock everythingโ€”test real behavior where practical + +**Integration Tests (THE SWEET SPOT)** +- Multiple units working together +- Tests behavior users actually experience +- Less brittle than unit tests, faster than E2E +- **This is where most of your tests should live** + +**E2E Tests (Playwright)** +- Critical user journeys only: login, checkout, core flows +- Expensive to write and maintain +- Reserve for flows where failure = business impact + +--- + +## Writing Effective Tests + +### Structure: Arrange-Act-Assert + +Every test should follow this pattern: + +```typescript +it('should reject invalid email during registration', async () => { + // Arrange: Set up the scenario + const invalidEmail = 'not-an-email'; + + // Act: Do the thing + const result = await registerUser({ email: invalidEmail, password: 'valid123' }); + + // Assert: Check the outcome + expect(result.success).toBe(false); + expect(result.error).toContain('email'); +}); +``` + +The **Act** section should be one line. If it's not, the test is probably doing too much. + +### Naming: Say What Breaks + +Test names should describe the behavior, not the implementation: + +**Good names:** +- `should reject registration with invalid email` +- `should show error message when API fails` +- `should preserve draft when navigating away` + +**Bad names:** +- `test email validation` (what about it?) +- `handleSubmit works` (what does "works" mean?) +- `test case 1` (no) + +### Test One Thing + +Each test should have **one reason to fail**. If a test fails, you should immediately know what broke. + +```typescript +// Bad: Testing multiple things +it('should handle registration', async () => { + // Tests validation, API call, redirect, AND email sending +}); + +// Good: Focused tests +it('should reject invalid email format', ...); +it('should call API with valid data', ...); +it('should redirect after successful registration', ...); +it('should send welcome email after registration', ...); +``` + +--- + +## Integration Tests in Practice + +Integration tests are the heart of Grove's testing strategy. Here's how to write them well. + +### Test User Behavior, Not Implementation + +```typescript +// Bad: Testing implementation +it('should set isLoading state to true', async () => { + const { component } = render(LoginForm); + await fireEvent.click(getByRole('button')); + expect(component.isLoading).toBe(true); // Testing internal state! +}); + +// Good: Testing user experience +it('should show loading indicator while logging in', async () => { + render(LoginForm); + await fireEvent.click(getByRole('button', { name: /sign in/i })); + expect(getByRole('progressbar')).toBeInTheDocument(); +}); +``` + +### Use Accessible Queries + +Query elements the way users find them: + +```typescript +// Priority order (best to worst): +getByRole('button', { name: /submit/i }) // How screen readers see it +getByLabelText('Email') // Form fields +getByText('Welcome back') // Visible text +getByTestId('login-form') // Last resort +``` + +### Don't Over-Mock + +Mocks remove confidence in the integration. Use them sparingly: + +```typescript +// Over-mocked: False confidence +vi.mock('./api'); +vi.mock('./validation'); +vi.mock('./utils'); +// You're testing... nothing real + +// Better: Mock at boundaries +vi.mock('./external-api'); // Mock the network, not your code +// Let validation, utils, etc. run for real +``` + +**Rule of thumb:** If you're mocking something you wrote, reconsider. + +--- + +## When Tests Break + +Tests that break are telling you something. Listen. + +### Good Breaks (Expected) + +- **Feature changed** โ€” Test caught that behavior shifted. Update the test. +- **Bug fixed** โ€” Old test was wrong. Fix it. +- **Requirement changed** โ€” Test reflects old requirement. Update it. + +### Bad Breaks (Symptoms of Poor Tests) + +- **Refactored internal code** โ€” Test was coupled to implementation. Rewrite it. +- **Changed CSS class** โ€” Test was querying implementation details. Use accessible queries. +- **Reordered code** โ€” Test depended on execution order. Make it order-independent. + +**If refactoring frequently breaks tests, your tests are testing the wrong things.** + +--- + +## The Bug โ†’ Test Pipeline + +Every production bug should become a test: + +1. **Bug reported** โ€” User can't check out with certain items +2. **Reproduce locally** โ€” Find the exact conditions +3. **Write failing test** โ€” Captures the bug's conditions +4. **Fix the bug** โ€” Test now passes +5. **Test prevents regression** โ€” Bug can never return + +This is one of the highest-value testing practices. It turns pain into protection. + +--- + +## Anti-Patterns to Avoid + +### The Ice Cream Cone + +``` + โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ + โ”‚ Many E2E tests โ”‚ โ† Slow, brittle, expensive + โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + โ•ญโ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ•ฎ + โ”‚ Few int. โ”‚ + โ•ฐโ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ•ฏ + โ•ญโ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ•ฎ + โ”‚ Few โ”‚ + โ”‚ unit โ”‚ + โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ +``` + +This is backwards. E2E tests are expensive. Integration tests give the best ROI. + +### Testing Implementation Details + +```typescript +// Testing implementation (bad) +expect(component.state.items).toHaveLength(3); +expect(handleClick).toHaveBeenCalledWith({ id: 1 }); + +// Testing behavior (good) +expect(getByRole('list').children).toHaveLength(3); +expect(getByText('Item added!')).toBeInTheDocument(); +``` + +### Coverage Theater + +Chasing 100% coverage leads to bad tests: + +```typescript +// Written only to hit coverage, provides zero value +it('should have properties', () => { + const user = new User(); + expect(user.email).toBeDefined(); + expect(user.name).toBeDefined(); +}); +``` + +Coverage is a **signal**, not a **goal**. High coverage with bad tests is worse than moderate coverage with good tests. + +### Snapshot Abuse + +Snapshots are useful for: +- Complex serialized output +- Error message formatting +- API response shapes + +Snapshots are harmful for: +- UI components (break on every style change) +- Anything with timestamps or random IDs +- Large objects (nobody reviews 500-line snapshot diffs) + +--- + +## The Grove Testing Workflow + +When asked to add tests, follow this workflow: + +### 1. Understand the Feature + +What does this feature **do** for users? Not how it's implementedโ€”what value does it provide? + +### 2. Identify Critical Paths + +What would break if this feature failed? Those are your test cases. + +### 3. Write Integration Tests First + +Start with tests that exercise real user behavior. Add unit tests only for complex logic. + +### 4. Keep Tests Close to Code + +``` +src/ +โ””โ”€โ”€ lib/ + โ””โ”€โ”€ features/ + โ””โ”€โ”€ auth/ + โ”œโ”€โ”€ login.ts + โ”œโ”€โ”€ login.test.ts โ† Right next to the code + โ””โ”€โ”€ register.ts +``` + +### 5. Run Tests Continuously + +```bash +npx vitest # Watch mode during development +npx vitest run # CI verification +``` + +--- + +## Quick Decision Guide + +| Situation | Action | +|-----------|--------| +| New feature | Write integration tests for user-facing behavior | +| Bug fix | Write test that reproduces bug first, then fix | +| Refactoring | Run existing tests; if they break on safe changes, they're bad tests | +| "Need more coverage" | Add tests for uncovered **behavior**, not uncovered lines | +| Pure function/algorithm | Unit test it | +| API endpoint | Integration test with mocked external services | +| UI component | Component test with Testing Library | +| Critical user flow | E2E test with Playwright | + +--- + +## Integration with Other Skills + +### javascript-testing + +Use `javascript-testing` for: +- Vitest configuration syntax +- Mocking patterns and APIs +- Assertion reference +- SvelteKit-specific test patterns + +### grove-documentation + +When writing test descriptions, follow Grove voice: +- Clear, direct names +- No jargon +- Say what the user experiences + +### code-quality + +Run linting and type checking before/after writing tests. Static analysis catches different bugs than tests do. + +--- + +## Self-Review Checklist + +Before considering tests "done": + +- [ ] Tests describe user behavior, not implementation +- [ ] Each test has one clear reason to fail +- [ ] Tests use accessible queries (getByRole, getByLabelText) +- [ ] Mocks are limited to external boundaries +- [ ] Test names explain what breaks when they fail +- [ ] No snapshot tests for volatile content +- [ ] Bug fixes include regression tests +- [ ] Tests run fast (seconds, not minutes) + +--- + +*Good tests let you ship with confidence. That's the whole point.* diff --git a/.claude/skills/grove-ui-design/SKILL.md b/.claude/skills/grove-ui-design/SKILL.md new file mode 100644 index 0000000..785a418 --- /dev/null +++ b/.claude/skills/grove-ui-design/SKILL.md @@ -0,0 +1,989 @@ +--- +name: grove-ui-design +description: Create warm, nature-themed UI for Grove with glassmorphism, seasonal decorations, randomized forests, and accessible design patterns. Use when building pages, enhancing UI, or adding decorative elements. +--- + +# Grove UI Design Skill + +## When to Activate + +Activate this skill when: +- Creating or enhancing pages for Grove sites +- Adding decorative nature elements (trees, clouds, weather effects) +- Implementing glassmorphism effects for readability +- Working with the seasonal theme system +- Building navigation patterns (navbar, mobile overflow menus) +- Creating "story" pages that guide users through content +- Ensuring mobile-friendly, accessible UI +- Choosing icons or visual elements + +## The Grove Aesthetic + +Grove is a **place**. It's nature-themed, warm, and invitingโ€”like a midnight tea shop with good documentation. + +### Core Principles + +``` +Warm, introspective, queer, unapologetically building something meaningful. +Write with the warmth of a midnight tea shop and the clarity of good documentation. +``` + +**Every design choice should feel:** +- **Welcoming** โ€” like entering a cozy space +- **Organic** โ€” natural, not rigid or corporate +- **Readable** โ€” content-first, decorations enhance, never obstruct +- **Alive** โ€” subtle animations, seasonal changes, randomization + +### User Identity Language + +Grove uses specific terms for community members in all UI: + +| Term | Who | Use For | +|------|-----|---------| +| **Wanderer** | Everyone | Greetings, welcome messages, all users | +| **Rooted** | Subscribers | Subscription confirmations, thank-yous | +| **Pathfinder** | Trusted guides | Community leaders (appointed) | +| **Wayfinder** | Autumn | The grove keeper (singular) | + +**In UI text:** +- "Welcome, Wanderer." (not "Welcome, user") +- "Welcome back, Wanderer." (dashboard greeting) +- "You've taken root." (subscription confirmation) +- "Thanks for staying rooted." (payment received) + +See `docs/grove-user-identity.md` for full documentation. + +--- + +## Glassmorphism Pattern + +Glass effects create readability while revealing hints of background decoration. + +### The Layering Formula + +``` +Background (gradients, vines, nature) + โ†“ +Decorative Elements (trees, clouds, particles) + โ†“ +Glass Surface (translucent + blur) + โ†“ +Content (text, cards, UI) +``` + +### Glass Components + +```svelte +import { Glass, GlassCard, GlassButton, GlassOverlay } from '@groveengine/ui/ui'; + + + +

Readable text over busy backgrounds

+
+ + + + Content here + + + +Subscribe +``` + +### Glass Variants + +| Variant | Use Case | Light Mode | Dark Mode | +|---------|----------|------------|-----------| +| `surface` | Headers, navbars | 95% white | 95% slate | +| `tint` | Text over backgrounds | 60% white | 50% slate | +| `card` | Content cards | 80% white | 70% slate | +| `accent` | Callouts, highlights | 30% accent | 20% accent | +| `overlay` | Modal backdrops | 50% black | 60% black | +| `muted` | Subtle backgrounds | 40% white | 30% slate | + +### CSS Utility Classes + +```html + +
Basic glass
+
Text container
+
Highlighted section
+ +``` + +### Key Pattern: Sticky Navigation + +```svelte + +``` + +--- + +## Seasonal Theme System + +Grove uses four seasons, each with distinct colors, weather effects, and moods. + +### Season Detection + +```svelte +import { season } from '$lib/stores/season'; + +const isSpring = $derived($season === 'spring'); +const isAutumn = $derived($season === 'autumn'); +const isWinter = $derived($season === 'winter'); +// Summer is the default (no flag needed) +``` + +### Color Palette System + +Import from: `@autumnsgrove/groveengine/ui/nature` or `$lib/components/nature/palette` + +#### Core Palettes (Year-Round) + +```typescript +import { greens, bark, earth, natural } from '@autumnsgrove/groveengine/ui/nature'; + +// Greens - organized dark-to-light for atmospheric depth +greens.darkForest // #0d4a1c - Background trees +greens.deepGreen // #166534 - Mid-distance +greens.grove // #16a34a - Grove brand primary +greens.meadow // #22c55e - Standard foliage +greens.spring // #4ade80 - Bright accent +greens.mint // #86efac - Light accent +greens.pale // #bbf7d0 - Foreground highlights + +// Bark - warm wood tones +bark.darkBark // #3d2817 - Oak, older trees +bark.bark // #5d4037 - Standard trunk +bark.warmBark // #6B4423 - Pine, cedar +bark.lightBark // #8b6914 - Young trees + +// Earth - ground elements +earth.soil, earth.mud, earth.clay, earth.sand, earth.stone, earth.pebble, earth.slate + +// Natural - cream and off-whites +natural.cream, natural.aspenBark, natural.bone, natural.mushroom, natural.birchWhite +``` + +#### Spring Palettes + +```typescript +import { springFoliage, springSky, wildflowers, cherryBlossoms, cherryBlossomsPeak } from '@autumnsgrove/groveengine/ui/nature'; + +// Spring Foliage - yellow-green new growth +springFoliage.sprout // #65a30d - Distant new growth +springFoliage.newLeaf // #84cc16 - Classic spring lime +springFoliage.freshGreen // #a3e635 - Bright foreground +springFoliage.budding // #bef264 - Pale new leaf +springFoliage.tender // #d9f99d - Very pale + +// Spring Sky +springSky.clear // #7dd3fc - Clear morning +springSky.soft // #bae6fd - Pale sky + +// Wildflowers - unified meadow flower colors +wildflowers.buttercup // #facc15 - Yellow +wildflowers.daffodil // #fde047 - Pale yellow +wildflowers.crocus // #a78bfa - Purple crocus +wildflowers.violet // #8b5cf6 - Wild violets +wildflowers.purple // #a855f7 - Lupine, thistle +wildflowers.lavender // #c4b5fd - Distant masses +wildflowers.tulipPink // #f9a8d4 - Pink tulips +wildflowers.tulipRed // #fb7185 - Red tulips +wildflowers.white // #fefefe - Daisies, trillium + +// Cherry Blossoms - summer standard +cherryBlossoms.deep // #db2777 - Dense centers +cherryBlossoms.standard // #ec4899 - Standard blossom +cherryBlossoms.light // #f472b6 - Light petals +cherryBlossoms.pale // #f9a8d4 - Pale blossoms +cherryBlossoms.falling // #fbcfe8 - Falling petals + +// Cherry Blossoms Peak - vibrant spring (one shade brighter!) +cherryBlossomsPeak.deep // #ec4899 +cherryBlossomsPeak.standard // #f472b6 +cherryBlossomsPeak.light // #f9a8d4 +cherryBlossomsPeak.pale // #fbcfe8 +cherryBlossomsPeak.falling // #fce7f3 +``` + +#### Unified Flowers Palette (NEW!) + +The `flowers` namespace consolidates all flower colors into one organized structure: + +```typescript +import { flowers } from '@autumnsgrove/groveengine/ui/nature'; + +// Meadow wildflowers (yellows, purples, pinks, whites) +flowers.wildflower.buttercup // #facc15 - Yellow +flowers.wildflower.daffodil // #fde047 - Pale yellow +flowers.wildflower.crocus // #a78bfa - Purple crocus +flowers.wildflower.violet // #8b5cf6 - Wild violets +flowers.wildflower.purple // #a855f7 - Lupine, thistle +flowers.wildflower.lavender // #c4b5fd - Distant masses +flowers.wildflower.tulipPink // #f9a8d4 - Pink tulips +flowers.wildflower.tulipRed // #fb7185 - Red tulips +flowers.wildflower.white // #fefefe - Daisies, trillium + +// Cherry blossoms - standard summer +flowers.cherry.deep // #db2777 +flowers.cherry.standard // #ec4899 +flowers.cherry.light // #f472b6 +flowers.cherry.pale // #f9a8d4 +flowers.cherry.falling // #fbcfe8 + +// Cherry blossoms at peak bloom - vibrant spring +flowers.cherryPeak.deep // #ec4899 +flowers.cherryPeak.standard // #f472b6 +flowers.cherryPeak.light // #f9a8d4 +flowers.cherryPeak.pale // #fbcfe8 +flowers.cherryPeak.falling // #fce7f3 +``` + +**Use `flowers.wildflower` instead of `accents.flower`** โ€” the accents version is deprecated. + +#### Autumn & Winter Palettes + +```typescript +import { autumn, autumnReds, winter } from '@autumnsgrove/groveengine/ui/nature'; + +// Autumn - warm fall foliage (dark-to-light for depth) +autumn.rust // #9a3412 - Deep background +autumn.ember // #c2410c - Oak-like +autumn.pumpkin // #ea580c - Maple mid-tones +autumn.amber // #d97706 - Classic fall +autumn.gold // #eab308 - Aspen/birch +autumn.honey // #facc15 - Bright foreground +autumn.straw // #fde047 - Pale dying leaves + +// Autumn Reds - cherry/maple fall foliage +autumnReds.crimson // #be123c - Deep maple +autumnReds.scarlet // #e11d48 - Bright cherry +autumnReds.rose // #f43f5e - Light autumn +autumnReds.coral // #fb7185 - Pale accent + +// Winter - frost, snow, ice + frosted evergreens +winter.snow, winter.frost, winter.ice, winter.glacier +winter.frostedPine, winter.winterGreen, winter.coldSpruce +winter.winterSky, winter.twilight, winter.overcast +winter.bareBranch, winter.frostedBark, winter.coldWood +winter.hillDeep, winter.hillMid, winter.hillNear, winter.hillFront +``` + +#### Accent Palettes + +```typescript +import { accents, wildflowers } from '@autumnsgrove/groveengine/ui/nature'; + +// Mushrooms - fairy tale pops of color +accents.mushroom.redCap, accents.mushroom.orangeCap, accents.mushroom.brownCap +accents.mushroom.spots, accents.mushroom.gill + +// Firefly - bioluminescence +accents.firefly.glow, accents.firefly.warmGlow, accents.firefly.body + +// Berry - rich saturated +accents.berry.ripe, accents.berry.elderberry, accents.berry.red + +// Water - cool blue spectrum +accents.water.surface, accents.water.deep, accents.water.shallow, accents.water.lily + +// Sky - time of day +accents.sky.dayLight, accents.sky.dayMid, accents.sky.sunset, accents.sky.night, accents.sky.star + +// Birds - species-specific colors +accents.bird.cardinalRed, accents.bird.cardinalMask, accents.bird.cardinalBeak +accents.bird.chickadeeCap, accents.bird.chickadeeBody, accents.bird.chickadeeBelly +accents.bird.robinBody, accents.bird.robinBreast, accents.bird.robinBeak +accents.bird.bluebirdBody, accents.bird.bluebirdWing, accents.bird.bluebirdBreast + +// NOTE: accents.flower is deprecated - use flowers.wildflower instead +``` + +#### Seasonal Helper Functions + +```typescript +import { getSeasonalGreens, getCherryColors, isTreeBare, pickRandom, pickFrom } from '@autumnsgrove/groveengine/ui/nature'; + +// Get foliage colors mapped to season +const foliage = getSeasonalGreens(season); +// spring โ†’ springFoliage colors +// summer โ†’ greens +// autumn โ†’ autumn palette +// winter โ†’ frosted evergreen colors + +// Get cherry tree colors by season +const cherryColors = getCherryColors(season); +// spring โ†’ cherryBlossomsPeak (vibrant!) +// summer โ†’ cherryBlossoms (standard) +// autumn โ†’ autumnReds +// winter โ†’ null (bare tree) + +// Check if deciduous tree is bare +if (isTreeBare('cherry', 'winter')) { /* no foliage */ } + +// Random color selection for natural variation +const randomGreen = pickRandom(greens); +const specificGreen = pickFrom(greens, ['grove', 'meadow']); +``` + +#### Deprecated Aliases (Still Work) + +```typescript +// These work but will be removed in v1.0: +import { spring, pinks, springBlossoms } from '@autumnsgrove/groveengine/ui/nature'; + +// spring โ†’ use springFoliage, wildflowers, springSky instead +// pinks โ†’ use cherryBlossoms instead +// springBlossoms โ†’ use cherryBlossomsPeak instead +// accents.flower โ†’ use flowers.wildflower instead +``` + +#### Season Mood Summary + +| Season | Primary Colors | Mood | +|--------|---------------|------| +| **Spring** | `springFoliage`, `cherryBlossomsPeak`, `wildflowers` | Renewal, hope | +| **Summer** | `greens`, `cherryBlossoms` | Growth, warmth | +| **Autumn** | `autumn`, `autumnReds` | Harvest, reflection | +| **Winter** | `winter` (frost, snow, frosted pines) | Rest, stillness | + +### Seasonal Weather Effects + +```svelte + +{#if isWinter} + +{/if} + + +{#if isSpring} + +{/if} + + +{#if isAutumn} + +{/if} +``` + +### Seasonal Background Gradients + +```svelte +
+``` + +### When to Use Seasons + +- **Roadmap pages** โ€” Show progress through seasonal metaphor +- **Story/about pages** โ€” Create atmosphere and emotional connection +- **Interactive demos** โ€” Let users toggle seasons (like /forest) +- **Help articles** โ€” Consider seasonal decor to break up long content +- **Anywhere you want magic** โ€” Use judgment based on page purpose + +--- + +## Randomized Forests + +The forest should feel alive and different every visit. + +### Tree Generation Pattern + +```typescript +interface GeneratedTree { + id: number; + x: number; // percentage from left (5-93% to avoid edges) + size: number; // base width in pixels + aspectRatio: number; // height = size * aspectRatio (1.0-1.5 range) + treeType: TreeType; // 'logo' | 'pine' | 'cherry' | 'aspen' | 'birch' + opacity: number; // 0.5-0.9 for depth + zIndex: number; // larger trees = higher z-index +} + +// Aspect ratio creates natural height variation +const TREE_ASPECT_RATIO_RANGE = { min: 1.0, max: 1.5 }; + +function generateSectionTrees(count: number): GeneratedTree[] { + const trees: GeneratedTree[] = []; + const usedPositions: number[] = []; + + for (let i = 0; i < count; i++) { + // Find non-overlapping position + let x: number; + let attempts = 0; + do { + x = 5 + Math.random() * 88; + attempts++; + } while (usedPositions.some(pos => Math.abs(pos - x) < 8) && attempts < 20); + usedPositions.push(x); + + const size = 80 + Math.random() * 80; + const aspectRatio = 1.0 + Math.random() * 0.5; + const opacity = 0.5 + Math.random() * 0.4; + const zIndex = size > 130 ? 3 : size > 100 ? 2 : 1; + + trees.push({ id: i, x, size, aspectRatio, treeType: pickRandom(treeTypes), opacity, zIndex }); + } + + return trees.sort((a, b) => a.x - b.x); +} +``` + +### Regeneration Timing + +- **On mount** โ€” Trees generate once when page loads +- **On resize (significant)** โ€” Only if viewport bracket changes dramatically +- **Never on scroll** โ€” Keep forest stable during reading + +### Rendering Trees + +```svelte +{#each forestTrees as tree (tree.id)} +
+ {#if tree.treeType === 'logo'} + + {:else if tree.treeType === 'pine'} + + {:else if tree.treeType === 'cherry'} + + {:else if tree.treeType === 'aspen'} + + {:else if tree.treeType === 'birch'} + + {/if} +
+{/each} +``` + +### Responsive Density + +```typescript +function calculateDensity(): number { + const width = window.innerWidth; + if (width < 768) return 1; // Mobile: base count + if (width < 1024) return 1.3; // Tablet + if (width < 1440) return 1.8; // Desktop + if (width < 2560) return 2.5; // Large desktop + return 3.5; // Ultrawide +} +``` + +--- + +## Nature Components + +Grove has an extensive library of decorative components. Explore with: + +```bash +# Trees +ls landing/src/lib/components/trees/ +ls landing/src/lib/components/nature/trees/ + +# Weather (seasonal particles) +ls landing/src/lib/components/nature/weather/ + +# Sky (clouds, stars, moon) +ls landing/src/lib/components/nature/sky/ + +# Botanical (leaves, petals, vines) +ls landing/src/lib/components/nature/botanical/ + +# Ground (flowers, grass, mushrooms) +ls landing/src/lib/components/nature/ground/ + +# Structural (lattice, lanterns, paths) +ls landing/src/lib/components/nature/structural/ + +# Birds (cardinals, robins, bluebirds) +ls landing/src/lib/components/nature/creatures/ +``` + +### Key Components + +| Component | Use | Example Props | +|-----------|-----|---------------| +| `Logo` | Grove tree, seasonal | `season`, `animate`, `breathing` | +| `TreePine` | Evergreen, stays green in autumn | `season`, `animate` | +| `TreeCherry` | Blossoms in spring, bare in winter | `season`, `animate` | +| `TreeAspen` / `TreeBirch` | Deciduous, seasonal colors | `season`, `animate` | +| `Cloud` | Decorative sky element | `variant`, `animate`, `speed`, `direction` | +| `SnowfallLayer` | Winter particles | `count`, `opacity`, `spawnDelay` | +| `FallingPetalsLayer` | Spring cherry blossoms | `count`, `opacity`, `fallDuration` | +| `FallingLeavesLayer` | Autumn leaves (tied to trees) | `trees`, `season` | +| `Cardinal` / `Chickadee` | Winter birds | `facing` | +| `Robin` / `Bluebird` | Spring birds | `facing` | +| `Vine` | Decorative ivy/vines | varies | +| `Lantern` | Warm glow points | varies | + +### Birds by Season + +```svelte + +{#if isWinter} + + +{/if} + + +{#if isSpring} + + +{/if} +``` + +--- + +## Midnight Bloom Palette + +For **dreamy**, **far-future**, **mystical** content. The tea shop that exists at the edge of tomorrow. + +```typescript +import { midnightBloom } from '$lib/components/nature/palette'; + +// Available colors: +midnightBloom.deepPlum // #581c87 - Night sky depth +midnightBloom.purple // #7c3aed - Soft purple glow +midnightBloom.violet // #8b5cf6 - Lighter accent +midnightBloom.amber // #f59e0b - Lantern warmth +midnightBloom.warmCream // #fef3c7 - Tea steam, page glow +midnightBloom.softGold // #fcd34d - Fairy lights +``` + +### Midnight Bloom Styling + +```svelte +
+ + + + + + + + + + +
+

Dreamy quote here...

+
+
+``` + +--- + +## Icons: Lucide Only + +**NEVER** use emojis. **ALWAYS** use Lucide icons. + +```svelte +import { MapPin, Check, Leaf, Trees, Mail } from 'lucide-svelte'; + + + + + + + +``` + +### Standardized Icon Mapping + +Use these icons consistently across the project: + +| Concept | Icon | Notes | +|---------|------|-------| +| **Navigation** | | | +| Home | `Home` | | +| About | `Info` | | +| Vision | `Telescope` | Looking forward | +| Roadmap | `Map` | Journey/direction | +| Pricing | `HandCoins` | Money/currency | +| Knowledge | `BookOpen` | Learning/docs | +| Forest | `Trees` | Community blogs | +| Blog | `PenLine` | Writing | +| **Features** | | | +| Email | `Mail` | | +| Storage | `HardDrive` | | +| Theming | `Palette` | Customization | +| Authentication | `ShieldCheck` | Security | +| Cloud | `Cloud` | Remote/serverless | +| Search | `SearchCode` | Code/advanced search | +| Archives | `Archive` | Backups | +| Upload | `Upload` | | +| Video | `Video` | | +| Comments | `MessagesSquare` | User discussions | +| GitHub | `Github` | External links to GitHub | +| **States** | | | +| Success | `Check` | Completed/valid | +| Error | `X` | Failed/close | +| Loading | `Loader2` | With animate-spin | +| **Content** | | | +| Posts | `FileText` | Blog posts | +| Tags | `Tag` | Categorization | +| Growth | `Sprout` | Grove brand, new beginnings | +| Heart | `Heart` | Love, care | +| External | `ExternalLink` | Opens new tab | +| Location | `MapPin` | Current position | +| **Phases** | | | +| Coming Soon | `Seedling` | Something growing | +| Refinement | `Gem` | Polish, quality | +| The Dream | `Sparkles` | Mystical (use sparingly!) | +| Night | `Star` | Midnight themes | +| **Actions** | | | +| Getting Started | `Compass` | Guidance | +| What's New | `Megaphone` | Announcements | +| Next Steps | `Lightbulb` | Ideas | + +### Icon Mapping Tables in Files + +Create a consistent icon map at the top of each component/page that uses icons: + +```typescript +// landing/src/lib/utils/icons.ts - Centralized icon registry +import { + Mail, HardDrive, Palette, ShieldCheck, Cloud, SearchCode, + Archive, Upload, MessagesSquare, Github, Check, X, Loader2, + FileText, Tag, Sprout, Heart, ExternalLink, MapPin, // ... etc +} from 'lucide-svelte'; + +export const featureIcons = { + mail: Mail, + harddrive: HardDrive, + palette: Palette, + shieldcheck: ShieldCheck, + cloud: Cloud, + searchcode: SearchCode, + // ... all mapped icons +} as const; + +export const stateIcons = { + success: Check, + error: X, + loading: Loader2, +} as const; +``` + +Then use in components: + +```svelte + + +{#each features as feature} + +{/each} +``` + +**Benefits:** +- Single source of truth for all icons +- Prevents undefined icon errors +- Easy to maintain and extend +- Reusable across entire project + +### Icon Usage Guidelines + +1. **Always use icon maps** - Never hardcode icon imports in every component +2. **Avoid overusing Sparkles** - Reserve for truly mystical/magical contexts +3. **Be consistent** - Use the same icon for the same concept everywhere +4. **Semantic meaning** - Choose icons that convey meaning, not just decoration +5. **Export from central utility** - Use `landing/src/lib/utils/icons.ts` for all icon sets + +### Icon Sizing + +```svelte + + + Feature name + + + + + + + +``` + +--- + +## Icon Composition (Building Block Pattern) + +**Philosophy:** "The grove doesn't need to be drawn. It just needs to be arranged." + +For creating custom logos, illustrations, or decorative elements, compose existing Lucide icons rather than drawing custom SVG from scratch. This ensures visual consistency with the icon system. + +### Why This Pattern? + +- **Consistency** โ€” Icons match the Lucide aesthetic (24x24 grid, 2px strokes, round caps) +- **Minimal custom code** โ€” Let Lucide do the heavy lifting +- **Maintainable** โ€” Updating Lucide updates your compositions +- **MIT licensed** โ€” All paths come from open-source icons + +### How to Extract Lucide Paths + +Lucide icons use a 24ร—24 viewBox with 2px strokes. Extract paths directly from source: + +```bash +# Find icon paths in Lucide source +curl -s https://raw.githubusercontent.com/lucide-icons/lucide/main/icons/tree-pine.svg +# Look for the elements +``` + +**Key Lucide icon paths for Grove compositions:** + +```typescript +// TreePine - conifer silhouette +const treePine = { + canopy: 'm17 14 3 3.3a1 1 0 0 1-.7 1.7H4.7a1 1 0 0 1-.7-1.7L7 14h-.3a1 1 0 0 1-.7-1.7L9 9h-.2A1 1 0 0 1 8 7.3L12 3l4 4.3a1 1 0 0 1-.8 1.7H15l3 3.3a1 1 0 0 1-.7 1.7H17Z', + trunk: 'M12 22v-3' +}; + +// TreeDeciduous - deciduous/round tree +const treeDeciduous = { + canopy: 'M8 19a4 4 0 0 1-2.24-7.32A3.5 3.5 0 0 1 9 6.03V6a3 3 0 1 1 6 0v.04a3.5 3.5 0 0 1 3.24 5.65A4 4 0 0 1 16 19Z', + trunk: 'M12 19v3' +}; + +// Moon - crescent moon +const moon = 'M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401'; + +// Flame - campfire/hearth +const flame = 'M12 3q1 4 4 6.5t3 5.5a1 1 0 0 1-14 0 5 5 0 0 1 1-3 1 1 0 0 0 5 0c0-2-1.5-3-1.5-5q0-2 2.5-4'; +``` + +### Composing with SVG Transforms + +Use `` to position, scale, and rotate icons: + +```svelte + + + + + + + + + + + + + + + + + +``` + +### Transform Cheatsheet + +| Transform | Effect | Example | +|-----------|--------|---------| +| `translate(x, y)` | Move origin | `translate(20, 8)` moves icon right 20, down 8 | +| `scale(s)` | Uniform size | `scale(0.65)` makes icon 65% size | +| `rotate(deg, cx, cy)` | Rotation around point | `rotate(-5, 12, 12)` tilts 5ยฐ around center | +| Combined | Chain transforms | `translate(20, 8) scale(0.65) rotate(-5, 12, 12)` | + +### Example: Grove Logo Compositions + +See `/landing/src/lib/components/logo-concepts/` for real implementations: + +| Logo | Composition | +|------|-------------| +| `LogoFireflyForest` | TreePine + TreeDeciduous + glowing circles | +| `LogoGatheringHearth` | Two trees angled toward center Flame | +| `LogoStarlightPines` | Two TreePines + Moon + star circles | +| `LogoShelter` | Two TreePines forming archway + Moon | +| `LogoWinterGrove` | TreePines + snow line accents | + +### Guidelines + +1. **Use Lucide paths as primary structure** โ€” Trees, moon, flame, etc. +2. **Custom SVG only for simple primitives** โ€” circles (fireflies), lines (ground, snow) +3. **Maintain Lucide styling** โ€” 2px strokes, round caps/joins, consistent opacity +4. **Create depth with opacity/scale** โ€” Larger = foreground (opacity 0.9), smaller = background (0.5-0.7) +5. **Keep viewBox aspect ratios reasonable** โ€” 40ร—32 or 48ร—32 for horizontal compositions + +### When to Use + +- **Logos & branding** โ€” Compose icons into unique marks +- **Illustrations** โ€” Scene building (forest, sky, etc.) +- **Custom icons** โ€” When Lucide doesn't have exactly what you need +- **Seasonal variations** โ€” Same composition, different elements (snow, blossoms) + +--- + +## Mobile Considerations + +### Overflow Menu Pattern + +Desktop navigation items that don't fit should go to a mobile sheet menu: + +```svelte + + + + + mobileMenuOpen = false} /> +``` + +### Decorative Elements on Mobile + +| Element | Mobile Treatment | +|---------|-----------------| +| Trees | Reduce count, simplify (density multiplier = 1) | +| Particles | Reduce count (40โ†’20 snowflakes) | +| Clouds | Hide some, keep 2-3 | +| Complex animations | Reduce or disable | +| Touch targets | Minimum 44x44px | + +### Performance Guidelines + +```svelte + + + + +{#if !prefersReducedMotion} + +{/if} +``` + +--- + +## When to Use + +| Pattern | Good For | +|---------|----------| +| **Glassmorphism** | Text over backgrounds, navbars, cards, modals | +| **Randomized forests** | Story pages, about pages, visual sections | +| **Seasonal themes** | Roadmaps, timelines, emotional storytelling | +| **Midnight Bloom** | Future features, dreams, mystical content | +| **Weather particles** | Hero sections, transitions between seasons | +| **Birds** | Adding life to forest scenes, seasonal indicators | + +## When NOT to Use + +| Pattern | Avoid When | +|---------|------------| +| **Heavy decoration** | Data-dense pages, admin interfaces, forms | +| **Particle effects** | Performance-critical pages, accessibility concerns | +| **Seasonal colors** | Brand-critical contexts needing consistent colors | +| **Multiple glass layers** | Can cause blur performance issues | +| **Randomization** | Content that needs to match between sessions | +| **Complex forests** | Mobile-first pages, simple informational content | + +--- + +## Reference Pages + +Study these for implementation patterns: + +- **`/forest`** โ€” Full randomized forest with all seasons +- **`/roadmap`** โ€” Seasonal sections, progressive decoration, midnight bloom +- **`/vision`** โ€” Narrative page with glass callouts + +--- + +## OG Images (Social Previews) + +Grove uses dynamic OG images for social media previews (Discord, Twitter, iMessage, etc.). + +### Architecture + +OG images are generated by a separate Cloudflare Worker at `og.grove.place` due to WASM bundling limitations with SvelteKit + Cloudflare Pages. + +``` +grove.place/api/og?title=X + โ†“ 302 redirect +og.grove.place/?title=X + โ†“ workers-og +PNG image (1200ร—630) +``` + +### API + +``` +GET https://og.grove.place/?title=X&subtitle=Y&accent=HEX +``` + +| Param | Default | Description | +|-------|---------|-------------| +| `title` | "Grove" | Main title (max 100 chars) | +| `subtitle` | "A place to Be." | Subtitle (max 200 chars) | +| `accent` | "16a34a" | Hex color without # (forest green) | + +### Adding OG to New Pages + +Use the SEO component which handles OG meta tags: + +```svelte + + + +``` + +### Files + +- `packages/og-worker/` โ€” Standalone Worker (uses `workers-og`) +- `landing/src/routes/api/og/+server.ts` โ€” Proxy to og.grove.place +- `landing/src/lib/components/SEO.svelte` โ€” Meta tag management + +--- + +## Integration with Other Skills + +When writing text for Grove UI (tooltips, buttons, onboarding, error messages), invoke the **grove-documentation** skill first. The voice should match the visuals. + +**Typical flow:** +1. Design the UI component/page +2. Activate `grove-documentation` for any user-facing text +3. Write content following Grove voice principles +4. Return to visual implementation + +--- + +## Quick Checklist + +Before shipping a Grove page: + +- [ ] Glass effects used for text readability over busy backgrounds? +- [ ] Lucide icons, no emojis? +- [ ] Mobile overflow menu for navigation items? +- [ ] Decorative elements respect `prefers-reduced-motion`? +- [ ] Touch targets at least 44x44px? +- [ ] Seasonal colors match the page's emotional tone? +- [ ] Trees randomized with proper spacing (8% minimum gap)? +- [ ] Dark mode supported with appropriate glass variants? +- [ ] User-facing text follows Grove voice (see `grove-documentation`)? diff --git a/.claude/skills/heartwood-auth/SKILL.md b/.claude/skills/heartwood-auth/SKILL.md new file mode 100644 index 0000000..82b2891 --- /dev/null +++ b/.claude/skills/heartwood-auth/SKILL.md @@ -0,0 +1,307 @@ +--- +name: heartwood-auth +description: Integrate Heartwood (GroveAuth) authentication into Grove applications. Use when adding sign-in, protecting routes, or validating sessions in any Grove property. +--- + +# Heartwood Auth Integration Skill + +## When to Activate + +Activate this skill when: +- Adding authentication to a Grove application +- Protecting admin routes +- Validating user sessions +- Setting up OAuth sign-in +- Integrating with Heartwood (GroveAuth) + +## Overview + +**Heartwood** is Grove's centralized authentication service powered by Better Auth. + +| Domain | Purpose | +|--------|---------| +| `heartwood.grove.place` | Frontend (login UI) | +| `auth-api.grove.place` | Backend API | + +### Key Features + +- **OAuth Providers**: Google +- **Magic Links**: Click-to-login emails via Resend +- **Passkeys**: WebAuthn passwordless authentication +- **KV-Cached Sessions**: Sub-100ms validation +- **Cross-Subdomain SSO**: Single session across all .grove.place + +## Integration Approaches + +### Option A: Better Auth Client (Recommended) + +For new integrations, use Better Auth's client library: + +```typescript +// src/lib/auth/client.ts +import { createAuthClient } from 'better-auth/client'; + +export const auth = createAuthClient({ + baseURL: 'https://auth-api.grove.place' +}); + +// Sign in with Google +await auth.signIn.social({ provider: 'google' }); + +// Get current session +const session = await auth.getSession(); + +// Sign out +await auth.signOut(); +``` + +### Option B: Cookie-Based SSO (*.grove.place apps) + +For apps on `.grove.place` subdomains, sessions work automatically via cookies: + +```typescript +// src/hooks.server.ts +import type { Handle } from '@sveltejs/kit'; + +export const handle: Handle = async ({ event, resolve }) => { + // Check session via Heartwood API + const sessionCookie = event.cookies.get('better-auth.session_token'); + + if (sessionCookie) { + try { + const response = await fetch('https://auth-api.grove.place/api/auth/session', { + headers: { + Cookie: `better-auth.session_token=${sessionCookie}` + } + }); + + if (response.ok) { + const data = await response.json(); + event.locals.user = data.user; + event.locals.session = data.session; + } + } catch { + // Session invalid or expired + } + } + + return resolve(event); +}; +``` + +### Option C: Legacy Token Flow (Backwards Compatible) + +For existing integrations using the legacy OAuth flow: + +```typescript +// 1. Redirect to Heartwood login +const params = new URLSearchParams({ + client_id: 'your-client-id', + redirect_uri: 'https://yourapp.grove.place/auth/callback', + state: crypto.randomUUID(), + code_challenge: await generateCodeChallenge(verifier), + code_challenge_method: 'S256' +}); +redirect(302, `https://auth-api.grove.place/login?${params}`); + +// 2. Exchange code for tokens (in callback route) +const tokens = await fetch('https://auth-api.grove.place/token', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams({ + grant_type: 'authorization_code', + code: code, + redirect_uri: 'https://yourapp.grove.place/auth/callback', + client_id: 'your-client-id', + client_secret: env.HEARTWOOD_CLIENT_SECRET, + code_verifier: verifier + }) +}).then(r => r.json()); + +// 3. Verify token on protected routes +const user = await fetch('https://auth-api.grove.place/verify', { + headers: { Authorization: `Bearer ${tokens.access_token}` } +}).then(r => r.json()); +``` + +## Protected Routes Pattern + +### SvelteKit Layout Protection + +```typescript +// src/routes/admin/+layout.server.ts +import { redirect } from '@sveltejs/kit'; +import type { LayoutServerLoad } from './$types'; + +export const load: LayoutServerLoad = async ({ locals }) => { + if (!locals.user) { + throw redirect(302, '/auth/login'); + } + + return { + user: locals.user + }; +}; +``` + +### API Route Protection + +```typescript +// src/routes/api/protected/+server.ts +import { json, error } from '@sveltejs/kit'; +import type { RequestHandler } from './$types'; + +export const GET: RequestHandler = async ({ locals }) => { + if (!locals.user) { + throw error(401, 'Unauthorized'); + } + + return json({ message: 'Protected data', user: locals.user }); +}; +``` + +## Session Validation + +### Via Better Auth Session Endpoint + +```typescript +async function validateSession(sessionToken: string) { + const response = await fetch('https://auth-api.grove.place/api/auth/session', { + headers: { + Cookie: `better-auth.session_token=${sessionToken}` + } + }); + + if (!response.ok) return null; + + const data = await response.json(); + return data.session ? data : null; +} +``` + +### Via Legacy Verify Endpoint + +```typescript +async function validateToken(accessToken: string) { + const response = await fetch('https://auth-api.grove.place/verify', { + headers: { + Authorization: `Bearer ${accessToken}` + } + }); + + const data = await response.json(); + return data.active ? data : null; +} +``` + +## Client Registration + +To integrate a new app with Heartwood, you need to register it as a client. + +### 1. Generate Client Credentials + +```bash +# Generate a secure client secret +openssl rand -base64 32 +# Example: YKzJChC3RPjZvd1f/OD5zUGAvcouOTXG7maQP1ernCg= + +# Hash it for storage (base64url encoding) +echo -n "YOUR_SECRET" | openssl dgst -sha256 -binary | base64 | tr '+/' '-_' | tr -d '=' +``` + +### 2. Register in Heartwood Database + +```sql +INSERT INTO clients (id, name, client_id, client_secret_hash, redirect_uris, allowed_origins) +VALUES ( + lower(hex(randomblob(16))), + 'Your App Name', + 'your-app-id', + 'BASE64URL_HASHED_SECRET', + '["https://yourapp.grove.place/auth/callback"]', + '["https://yourapp.grove.place"]' +); +``` + +### 3. Set Secrets on Your App + +```bash +# Set the client secret on your app +wrangler secret put HEARTWOOD_CLIENT_SECRET +# Paste: YKzJChC3RPjZvd1f/OD5zUGAvcouOTXG7maQP1ernCg= +``` + +## Environment Variables + +| Variable | Description | +|----------|-------------| +| `HEARTWOOD_CLIENT_ID` | Your registered client ID | +| `HEARTWOOD_CLIENT_SECRET` | Your client secret (never commit!) | + +## API Endpoints Reference + +### Better Auth Endpoints (Recommended) + +| Method | Endpoint | Purpose | +|--------|----------|---------| +| POST | `/api/auth/sign-in/social` | OAuth sign-in | +| POST | `/api/auth/sign-in/magic-link` | Magic link sign-in | +| POST | `/api/auth/sign-in/passkey` | Passkey sign-in | +| GET | `/api/auth/session` | Get current session | +| POST | `/api/auth/sign-out` | Sign out | + +### Legacy Endpoints + +| Method | Endpoint | Purpose | +|--------|----------|---------| +| GET | `/login` | Login page | +| POST | `/token` | Exchange code for tokens | +| GET | `/verify` | Validate access token | +| GET | `/userinfo` | Get user info | + +## Best Practices + +### DO +- Use Better Auth client for new integrations +- Validate sessions on every protected request +- Use `httpOnly` cookies for token storage +- Implement proper error handling for auth failures +- Log out users gracefully when sessions expire + +### DON'T +- Store tokens in localStorage (XSS vulnerable) +- Skip session validation on API routes +- Hardcode client secrets +- Ignore token expiration + +## Cross-Subdomain SSO + +All `.grove.place` apps share the same session cookie automatically: + +``` +better-auth.session_token (domain=.grove.place) +``` + +Once a user signs in on any Grove property, they're signed in everywhere. + +## Troubleshooting + +### "Session not found" errors +- Check cookie domain is `.grove.place` +- Verify SESSION_KV namespace is accessible +- Check session hasn't expired + +### OAuth callback errors +- Verify redirect_uri matches registered client +- Check client_id is correct +- Ensure client_secret_hash uses base64url encoding + +### Slow authentication +- Ensure KV caching is enabled (SESSION_KV binding) +- Check for cold start issues (Workers may sleep) + +## Related Resources + +- **Heartwood Spec**: `/Users/autumn/Documents/Projects/GroveAuth/GROVEAUTH_SPEC.md` +- **Better Auth Docs**: https://better-auth.com +- **Client Setup Guide**: `/Users/autumn/Documents/Projects/GroveAuth/docs/OAUTH_CLIENT_SETUP.md` diff --git a/.claude/skills/museum-documentation/SKILL.md b/.claude/skills/museum-documentation/SKILL.md new file mode 100644 index 0000000..6af4268 --- /dev/null +++ b/.claude/skills/museum-documentation/SKILL.md @@ -0,0 +1,502 @@ +--- +name: museum-documentation +description: Write elegant, narrative-driven documentation that treats codebases and systems as exhibits worth exploring. Use when creating documentation for Wanderers and visitors who want to understand how Grove works. This is the "fancy" documentation styleโ€”warm, inviting, meant to be read and enjoyed. +--- + +# Museum Documentation + +> *Documentation as hospitality. Code as curated collection.* + +The art of transforming technical systems into welcoming guided tours. Museum documentation positions the writer as a guide walking alongside readers through "why" questions before diving into implementation specifics. + +This is Grove's elegant documentation styleโ€”meant for Wanderers of any experience level who want to understand the technologies, patterns, and decisions that make Grove what it is. + +## When to Activate + +- Creating documentation meant to be **read by Wanderers**, not developers +- Writing knowledge base articles that explain how systems work +- Documenting a codebase, feature, or system for curious visitors +- Creating "how it works" content for the help center +- Writing technical content that should feel inviting, not intimidating +- Building exhibits for future knowledge base sections +- Onboarding documentation that walks through architecture + +**Not for:** +- API references (use grove-documentation) +- Technical specs (use grove-spec-writing) +- Quick-reference guides + +--- + +## Core Philosophy + +Documentation should function as **hospitality**. + +When readers enter a codebase or system, they're visitors unfamiliar with its architecture and design decisions. Museum-style documentation positions the writer as a guide rather than a reference compiler, walking alongside readers through "why" questions before diving into implementation. + +### The Museum Metaphor + +``` + ๐ŸŒฒ Welcome ๐ŸŒฒ + โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ + โ”‚ โ”‚ + โ”‚ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ”‚ + โ”‚ โ”‚ EXHIBIT A โ”‚ โ”‚ + โ”‚ โ”‚ โ”‚ โ”‚ + โ”‚ โ”‚ How Login โ”‚ โ”‚ + โ”‚ โ”‚ Works โ”‚ โ”‚ + โ”‚ โ”‚ โ”‚ โ”‚ + โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ”‚ + โ”‚ โ”‚ โ”‚ + โ”‚ โ•โ•โ•โ•โ•โ•ชโ•โ•โ•โ•โ• โ”‚ + โ”‚ โ”‚ โ”‚ + โ”‚ โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ โ”‚ + โ”‚ โ”‚ EXHIBIT B โ”‚ โ”‚ + โ”‚ โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ โ”‚ + โ”‚ โ”‚ + โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ + + Walk through. Take your time. + Every exhibit tells a story. +``` + +A museum doesn't hand you a catalog and wish you luck. It **guides** you through a curated experience, placing context before complexity, stories before specifications. + +--- + +## Key Principles + +### Orient Before Explaining + +Start exhibits by establishing context. Before showing code or architecture, tell readers: +- What they're looking at +- Why it exists +- Who benefits from it + +**Instead of:** +> The TokenRefreshMap stores active refresh operations keyed by user ID. + +**Write:** +> When someone's login expires, we need to refresh their credentials without logging them out. This map coordinates that processโ€”preventing duplicate refresh attempts when multiple tabs are open. + +### Explain Reasoning Over Facts + +Code shows *what*. Documentation explains *why*. + +Rather than stating that a Map stores token refresh operations, describe the coordination problem it solves. Connect the abstraction to the experience it creates. + +### Use Accessible Metaphors + +Connect technical concepts to familiar experiences: + +| Technical Concept | Museum Metaphor | +|-------------------|-----------------| +| Database | A filing cabinet with organized drawers | +| Cache | A quick-lookup shelf by the door | +| Middleware | A security checkpoint you pass through | +| Queue | A line where requests wait their turn | +| Worker | A helpful assistant handling tasks in the background | +| Webhook | A doorbell that rings when something happens | + +### Show Real Code, Then Analyze + +Present actual code snippets followed by clear explanation of their significance: + +```typescript +const pending = this.refreshInProgress.get(userId); +if (pending) return pending; +``` + +*If a refresh is already happening for this person, we wait for that one instead of starting another. One kitchen, one cook.* + +--- + +## Structural Framework + +Museum exhibits follow consistent anatomy: + +### 1. Title with Tagline + +```markdown +# The Authentication Exhibit + +> Where login happens. Where trust begins. +``` + +### 2. "What You're Looking At" Section + +Orient the reader immediately: + +```markdown +## What You're Looking At + +This is where login happens. When someone proves they own an email +address, this code decides what they can access and how long that +access lasts. + +You'll see OAuth flows, session management, and token refresh logic. +Nothing scaryโ€”just careful choreography. +``` + +### 3. Organized Tour Structure + +Use galleries, parts, or sections to organize the journey: + +```markdown +## The Tour + +### Gallery 1: The Front Door +How visitors arrive and prove who they are. + +### Gallery 2: The Memory Room +How we remember who's logged in. + +### Gallery 3: The Renewal Office +How sessions stay fresh without interrupting work. +``` + +### 4. "Patterns Worth Stealing" + +Highlight transferable lessons: + +```markdown +## Patterns Worth Stealing + +**The "already in progress" check.** Before starting an expensive +operation, check if it's already running. Simple, but easy to forget. + +**Centralized error handling.** All auth failures flow through one +function. One place to fix, one place to log. +``` + +### 5. "Lessons Learned" + +Offer honest reflection: + +```markdown +## Lessons Learned + +We tried stateless JWTs first. Simpler, they said. Scalable, they +promised. But logout was impossibleโ€”tokens couldn't be revoked. + +Session-based auth is older, but it works. Sometimes boring is right. +``` + +### 6. "Continue Your Tour" + +Link to related exhibits: + +```markdown +## Continue Your Tour + +- **[The Database Exhibit](./database.md)** โ€” Where sessions are stored +- **[The API Exhibit](./api.md)** โ€” How protected routes check access +- **[The Security Exhibit](./security.md)** โ€” Rate limiting and protection +``` + +### 7. Meaningful Closing Signature + +```markdown +--- + +*โ€” Autumn, January 2026* +``` + +Or a poetic one-liner: + +```markdown +--- + +*Trust is built one verified request at a time.* +``` + +--- + +## Visual Elements + +### ASCII Flow Diagrams + +Show processes and relationships: + +``` + Visitor Grove Google + โ”‚ โ”‚ โ”‚ + โ”‚ "Log me in" โ”‚ โ”‚ + โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ + โ”‚ โ”‚ "Who is this?" โ”‚ + โ”‚ โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ + โ”‚ โ”‚ โ”‚ + โ”‚ โ”‚ "It's autumn@..." โ”‚ + โ”‚ โ”‚ <โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ + โ”‚ โ”‚ โ”‚ + โ”‚ "Welcome back" โ”‚ โ”‚ + โ”‚ <โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ + โ”‚ โ”‚ โ”‚ +``` + +### Tables for Quick Reference + +```markdown +| File | What It Does | Why It Matters | +|------|--------------|----------------| +| `auth.ts` | Handles OAuth flow | The front door | +| `session.ts` | Manages login state | The memory | +| `middleware.ts` | Checks every request | The bouncer | +``` + +### Code Blocks with Context + +Never show code in isolation. Always explain before or after: + +```typescript +// Every request passes through this checkpoint +export async function authGuard(request: Request): Promise { + const session = await getSession(request); + if (!session) { + return redirect('/login'); + } + return null; // Continue to the page +} +``` + +*If you're not logged in, you go to login. If you are, you continue. Simple checkpoint logic.* + +--- + +## Voice and Tone + +### Do + +- Write conversationally using "you" and "we" naturally +- Acknowledge imperfections ("We tried X first. It didn't work.") +- Include personal touches ("This took three attempts to get right.") +- Use short paragraphs (2-4 sentences) +- Vary sentence rhythm + +### Avoid + +- Em-dashes (use periods, commas, or parentheses) +- Corporate jargon ("robust," "seamless," "leverage") +- Heavy transitions ("Furthermore," "Moreover," "Additionally") +- Passive voice when active is clearer +- Hedging language ("This may potentially help...") + +### The Distinction + +**Generic (avoid):** +> This module provides robust functionality for handling authentication flows in a seamless manner, leveraging industry-standard OAuth protocols. + +**Museum style (use):** +> This is where login happens. When someone proves they own an email address, this code decides what they can access. + +--- + +## Organization Patterns + +### Full Codebase: MUSEUM.md + +For documenting an entire codebase, create a central `MUSEUM.md` that serves as the entrance: + +```markdown +# Welcome to the Grove Museum + +> A guided tour of how this forest grows. + +## The Wings + +- **[The Architecture Wing](./docs/exhibits/architecture.md)** โ€” The big picture +- **[The Authentication Exhibit](./docs/exhibits/auth.md)** โ€” Trust and identity +- **[The Database Galleries](./docs/exhibits/database.md)** โ€” Where data lives +``` + +### Single Directory: EXHIBIT.md + +For a single complex feature or directory: + +```markdown +# The Editor Exhibit + +> Where words become posts. + +This directory contains everything that powers the writing experience... +``` + +### Complex Features: Gallery Structure + +For multi-part systems, use galleries: + +```markdown +## Gallery 1: Data Layer +How posts are stored and retrieved. + +## Gallery 2: API Endpoints +The doors visitors knock on. + +## Gallery 3: The Editor Component +Where the magic happens in the browser. + +## Gallery 4: Security Considerations +Keeping things safe. +``` + +--- + +## Validation Checklist + +Before finalizing any museum documentation: + +### Structure +- [ ] Title includes tagline +- [ ] "What You're Looking At" orients the reader +- [ ] Organized into logical galleries/sections +- [ ] "Patterns Worth Stealing" highlights transferable lessons +- [ ] "Continue Your Tour" links to related content +- [ ] Meaningful closing (signature or poetic line) + +### Visual Variety +- [ ] At least one ASCII diagram or flow +- [ ] Tables where comparison helps +- [ ] Code blocks with explanatory context +- [ ] No walls of text longer than 4-5 paragraphs + +### Voice (refer to grove-documentation) +- [ ] No em-dashes +- [ ] No corporate jargon +- [ ] Direct tone explaining motivations +- [ ] Acknowledged imperfections where honest +- [ ] Clear connections between system parts + +### Reader Experience +- [ ] A newcomer could follow the tour +- [ ] "Why" is answered before "how" +- [ ] Technical details are contextualized +- [ ] The path feels logical and navigable + +--- + +## Integration with Other Skills + +### Before Writing + +1. **walking-through-the-grove** โ€” If the exhibit needs a name +2. **grove-documentation** โ€” Review voice guidelines, especially the "avoid" lists + +### While Writing + +3. **grove-spec-writing** โ€” Borrow ASCII art techniques for diagrams +4. **grove-documentation** โ€” Check terminology (Wanderer, Rooted, etc.) + +### After Writing + +5. **Read as a newcomer** โ€” Traverse the documentation as if you've never seen it +6. Does the path feel logical? Would you want to explore further? + +--- + +## Example: A Complete Exhibit + +```markdown +# The Session Exhibit + +> How Grove remembers who you are. + +## What You're Looking At + +When you log in, Grove needs to remember you. Not foreverโ€”just long +enough for your visit. This exhibit shows how that memory works. + +You'll see cookies, database tables, and the careful dance of +"who are you?" that happens with every page load. + +--- + +## Gallery 1: The Cookie Jar + +A session starts with a cookie. Not the chocolate chip kindโ€”a small +piece of text your browser holds onto. + +```typescript +const SESSION_COOKIE = 'grove_session'; +const SESSION_DURATION = 7 * 24 * 60 * 60 * 1000; // 7 days +``` + +*Seven days. Long enough to be convenient, short enough to stay secure.* + +When you log in, we generate a random ID and store it in this cookie. +The ID itself means nothingโ€”it's just a key to look you up. + +--- + +## Gallery 2: The Memory Book + +The actual session data lives in the database: + +| Column | What It Holds | +|--------|---------------| +| `id` | The random key from the cookie | +| `user_id` | Who this session belongs to | +| `created_at` | When you logged in | +| `expires_at` | When this session ends | + +Every time you load a page, we look up your cookie's ID in this table. +If we find it (and it hasn't expired), you're still logged in. + +--- + +## Gallery 3: The Refresh Dance + +Sessions expire. But logging in every week is annoying. + +So we do a quiet refresh: when your session is more than halfway +through its life, we extend it. You never notice. You just stay +logged in while you're active. + +```typescript +if (session.expiresAt < Date.now() + SESSION_DURATION / 2) { + await extendSession(session.id); +} +``` + +*Active visitors stay. Abandoned sessions expire.* + +--- + +## Patterns Worth Stealing + +**The "halfway refresh" pattern.** Don't wait until expiration to +extend sessions. Extend them while the visitor is active. + +**Random IDs over sequential.** Session IDs should be unpredictable. +Never use auto-incrementing numbers for security tokens. + +--- + +## Lessons Learned + +We used to store session data in the cookie itself (JWTs). Simpler, +we thought. But then we couldn't revoke sessionsโ€”if someone's token +leaked, we had no way to invalidate it. + +Database sessions are older technology. Sometimes older is wiser. + +--- + +## Continue Your Tour + +- **[The Authentication Exhibit](./auth.md)** โ€” How login happens +- **[The Security Exhibit](./security.md)** โ€” Rate limiting and protection + +--- + +*โ€” Autumn, January 2026* +``` + +--- + +## The Underlying Purpose + +Museum documentation respects readers' time and intelligence while acknowledging that code is knowledge deserving careful stewardship. + +Wanderers who read these exhibits should leave understanding not just *what* Grove does, but *why* it does it that way. They should feel like they've been welcomed into the workshop, not handed a manual. + +*Every codebase has stories. Museum documentation tells them.* diff --git a/.claude/skills/npm-publish/SKILL.md b/.claude/skills/npm-publish/SKILL.md new file mode 100644 index 0000000..59e0442 --- /dev/null +++ b/.claude/skills/npm-publish/SKILL.md @@ -0,0 +1,195 @@ +--- +name: npm-publish +description: Publish @autumnsgrove/groveengine to npm with proper registry swap workflow. Use when releasing a new version of the engine package to npm. +user_invocable: true +--- + +# npm Publish Skill + +Publish `@autumnsgrove/groveengine` to npm while keeping the default registry as GitHub Packages. + +## When to Activate + +Activate this skill when: +- User says "publish to npm" +- User says "release to npm" +- User says "bump and publish" +- User says "/npm-publish" + +## The Workflow + +**CRITICAL**: The package.json uses GitHub Packages by default. You MUST swap to npm, publish, then swap BACK. + +``` +1. Bump version in packages/engine/package.json +2. Swap publishConfig to npm registry +3. Build the package +4. Publish to npm +5. Swap publishConfig BACK to GitHub Packages +6. Commit the version bump +7. Push to remote +``` + +## Step-by-Step Execution + +### Step 1: Bump Version + +Edit `packages/engine/package.json`: + +```json +"version": "X.Y.Z", // Increment appropriately +``` + +Use semantic versioning: +- **MAJOR** (X): Breaking changes +- **MINOR** (Y): New features, backwards compatible +- **PATCH** (Z): Bug fixes, backwards compatible + +### Step 2: Swap to npm Registry + +**BEFORE** (GitHub Packages - default): +```json +"publishConfig": { + "registry": "https://npm.pkg.github.com" +}, +``` + +**AFTER** (npm - for publishing): +```json +"publishConfig": { + "registry": "https://registry.npmjs.org", + "access": "public" +}, +``` + +### Step 3: Build Package + +```bash +cd /Users/autumn/Documents/Projects/GroveEngine/packages/engine +pnpm run package +``` + +### Step 4: Publish to npm + +```bash +npm publish --access public +``` + +The `prepublishOnly` script runs `pnpm run package` automatically, so this may rebuild. + +Verify success with: +``` ++ @autumnsgrove/groveengine@X.Y.Z +``` + +### Step 5: Swap BACK to GitHub Packages + +**CRITICAL - DO NOT FORGET THIS STEP** + +Change `packages/engine/package.json` back to: + +```json +"publishConfig": { + "registry": "https://npm.pkg.github.com" +}, +``` + +### Step 6: Commit Version Bump + +```bash +cd /Users/autumn/Documents/Projects/GroveEngine +git add packages/engine/package.json +git commit -m "chore: bump version to X.Y.Z" +git push origin main +``` + +## Quick Reference Commands + +```bash +# From project root: + +# 1. Edit version in packages/engine/package.json +# 2. Edit publishConfig to npm registry + +# 3. Build and publish +cd packages/engine +pnpm run package +npm publish --access public + +# 4. Edit publishConfig back to GitHub + +# 5. Commit and push (from project root) +git add packages/engine/package.json +git commit -m "chore: bump version to X.Y.Z" +git push origin main +``` + +## Verification + +After publishing, verify on npm: + +```bash +npm view @autumnsgrove/groveengine version +``` + +Or visit: https://www.npmjs.com/package/@autumnsgrove/groveengine + +## Troubleshooting + +### OTP/2FA Error +``` +npm error code EOTP +npm error This operation requires a one-time password +``` + +**Solution**: Create a granular access token with "Bypass 2FA" enabled: +1. Go to https://www.npmjs.com/settings/autumnsgrove/tokens +2. Generate New Token โ†’ Granular Access Token +3. Enable "Bypass 2FA" +4. Set token: `npm config set //registry.npmjs.org/:_authToken=npm_YOUR_TOKEN` + +See `AgentUsage/npm_publish.md` for detailed token setup. + +### Package Already Published +``` +npm error 403 - You cannot publish over the previously published versions +``` + +**Solution**: You forgot to bump the version. Increment it and try again. + +### Wrong Registry in Commit +If you accidentally committed with npm registry, fix it: + +```bash +# Edit publishConfig back to GitHub +git add packages/engine/package.json +git commit --amend --no-edit +git push --force-with-lease origin main +``` + +## Registry Swap Reference + +| Registry | publishConfig | +|----------|---------------| +| **GitHub** (default) | `"registry": "https://npm.pkg.github.com"` | +| **npm** (for publish) | `"registry": "https://registry.npmjs.org", "access": "public"` | + +## Checklist + +Before starting: +- [ ] Decided on new version number +- [ ] All changes committed and pushed + +During publish: +- [ ] Version bumped in package.json +- [ ] publishConfig swapped to npm +- [ ] Package built successfully +- [ ] Published to npm (see `+ @autumnsgrove/groveengine@X.Y.Z`) +- [ ] publishConfig swapped BACK to GitHub +- [ ] Version bump committed +- [ ] Pushed to remote + +## Related + +- `AgentUsage/npm_publish.md` - Token setup and 2FA workaround +- `packages/engine/package.json` - Package configuration diff --git a/.claude/skills/walking-through-the-grove/SKILL.md b/.claude/skills/walking-through-the-grove/SKILL.md new file mode 100644 index 0000000..26ae3db --- /dev/null +++ b/.claude/skills/walking-through-the-grove/SKILL.md @@ -0,0 +1,248 @@ +--- +name: walking-through-the-grove +description: Find the right Grove-themed name for a new service or feature. Use when naming anything new in the Grove ecosystem. Involves reading the naming philosophy, creating a visualization scratchpad, and walking through the forest metaphor to find where the concept naturally fits. +--- + +# Walking Through the Grove + +A naming ritual for the Grove ecosystem. Use this when you need to find a name that *fits*โ€”not just a clever pun, but something that belongs in this forest. + +## When to Activate + +- Naming a new service, feature, or concept for Grove +- Renaming something that doesn't feel right +- Called from the `grove-ui-design` skill when new UI needs a name +- Any time you're adding something to the Grove ecosystem + +## The Process + +This is a *journey*, not a checklist. Take your time. + +### Step 1: Read the Naming Philosophy + +```bash +# Always start here +cat docs/grove-naming.md +``` + +Read the entire document. Don't skim. Let it sink in: +- "A forest of voices. Every user is a tree in the grove." +- Names aren't brandingโ€”they're the language of an ecosystem +- Things that grow, shelter, connect +- Not about trees directlyโ€”about what happens *in and around* the forest + +### Step 2: Create a Scratchpad + +Create a markdown file for your journey: + +```bash +mkdir -p docs/scratch +# Create: docs/scratch/{concept}-naming-journey.md +``` + +This scratchpad is where you think out loud. Include: +- ASCII art visualizations +- Questions you're asking yourself +- Rejected ideas and why +- The moment when something clicks + +### Step 3: Visualize the Grove + +In your scratchpad, draw the grove. ASCII art helps: + +``` + โ˜€๏ธ + ๐ŸŒฒ ๐ŸŒฒ ๐ŸŒฒ + ๐ŸŒฒ ๐ŸŒณ ๐ŸŒฒ + โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• + ROOTS CONNECT BENEATH + (mycelium network) +``` + +Place the existing services in the visualization: +- Where is Meadow? (the open social space) +- Where is Heartwood? (the core identity) +- Where is Ivy? (climbing, connecting) +- Where is Pantry? (the warm kitchen cupboard) + +### Step 4: Ask "What IS This Thing?" + +Don't ask "where does it go?" first. Ask: + +**What is it, fundamentally?** +- Is it a place? (Meadow, Nook, Clearing) +- Is it an object/process? (Amber, Bloom, Patina) +- Is it a feature of the tree? (Foliage, Heartwood, Rings) +- Is it a connection? (Ivy, Mycelium, Reeds) + +**What does it DO in the user's life?** +- Protect? (Shade, Patina) +- Connect? (Ivy, Meadow, Reeds) +- Store? (Amber, Trove) +- Guide? (Waystone, Trails) +- Create? (Terrarium, Foliage) + +**What emotion should it evoke?** +- Warmth? +- Safety? +- Discovery? +- Community? +- Privacy? + +### Step 5: Walk Through the Forest + +Imagine you're a user walking through the grove. Write this in your scratchpad: + +```markdown +## Walking Through... + +I enter the grove. I see... +I walk past the Meadow where others gather. +I find my treeโ€”my blog, my space. +I check my Rings (private growth). +I see my Foliage (how others see me). + +Now I need [THE NEW THING]. Where do I find it? +What does it look like? Who's there? How does it feel? +``` + +Let the scene guide you to the name. + +### Step 6: Generate Candidates + +Based on your walk, list 5-10 candidates. For each: + +```markdown +**[Name]** - `[name].grove.place` + +- What it means in nature +- Why it fits this concept +- The vibe/feeling +- Potential issues +``` + +### Step 7: Test the Tagline + +A good Grove name should complete this sentence naturally: + +> "[Name] is where you _______________." + +Or: + +> "[Name] is the _______________." + +If you can't write a poetic one-liner, the name might not fit. + +### Step 8: Write the Entry + +Once you've found the name, write it in Grove style: + +```markdown +## [Name] +**[Tagline]** ยท `[domain].grove.place` + +[2-3 sentences explaining what this thing IS in the real worldโ€” +the natural metaphor. Then 2-3 sentences explaining what it does +in Grove. End with the feeling it should evoke.] + +*[A poetic one-liner in italics]* +``` + +### Step 9: Check for Conflicts + +Before finalizing: +- Search the codebase for the name +- Check if the subdomain concept conflicts with existing services +- Make sure it's not too similar to existing names +- Consider how it sounds spoken aloud + +### Step 10: Implement + +Update all the files: +1. `docs/grove-naming.md` โ€” Add the full entry +2. `packages/grove-router/src/index.ts` โ€” Claim subdomain +3. `plant/src/routes/api/check-username/+server.ts` โ€” Reserve username +4. Workshop page if applicable +5. Icons if applicable + +--- + +## Philosophy Reminders + +From the naming document: + +> "These names share common ground: nature, shelter, things that grow. But none of them are *about* trees directly. They're about what happens in and around the forest." + +> "The Grove is the place. These are the things you find there." + +The name should feel **inevitable**โ€”like it was always there, waiting to be discovered. + +--- + +## Example Journey: Finding "Porch" + +The problem: We need a name for support tickets. + +**First attempts (rejected):** +- Echo โ†’ "echo chamber" feels like shouting into void, no one listening +- Feather, Flare, Dove โ†’ These are about *sending* something +- But support isn't about sendingโ€”it's about *connecting* + +**The walk:** +> I'm in the grove. Something's wrong with my tree. I need help. +> Waystone gives me self-service guides. Clearing shows me status. +> But I need to actually *talk* to someone. +> +> What do I do? +> +> I walk to... a cabin. There's a porch. Someone's there. +> I sit down. We talk about what's going on. + +**The realization:** +Support isn't a ticket system. It's a porch conversation. + +**The name:** Porch + +> A porch on a cabin in the woods. You come up the steps. You sit down. +> The grove keeper comes out. You talk. + +*"Have a seat on the porch. We'll figure it out together."* + +--- + +## Integration with Other Skills + +### grove-ui-design + +When the `grove-ui-design` skill encounters something that needs naming: + +1. Pause the UI work +2. Invoke this skill +3. Complete the naming journey +4. Return to UI work with the new name + +This keeps the naming intentional rather than rushed. + +### grove-documentation + +After finding the right name, you'll need to write its description. Invoke the **grove-documentation** skill when: + +1. Writing the entry for `docs/grove-naming.md` +2. Crafting the tagline +3. Writing the poetic one-liner + +The naming document entries should follow Grove's voice: warm, direct, avoiding AI patterns. The `grove-documentation` skill has the full guidelines. + +--- + +## The Scratchpad is Sacred + +Keep your scratchpad files. They're documentation of how we think about Grove: + +``` +docs/scratch/ + grove-journey.md โ† The original Porch discovery + {feature}-naming.md โ† Future naming journeys +``` + +These become part of Grove's story. diff --git a/AGENT.md b/AGENT.md index 800303c..1cf81e6 100644 --- a/AGENT.md +++ b/AGENT.md @@ -55,8 +55,10 @@ Shutter is a web content distillation service that sits between LLM agents and r ### TODO Management - **Always check `TODOS.md` first** when starting a task or session +- **Check `COMPLETED.md`** for context on past decisions and implementation details - **Update immediately** when tasks are completed, added, or changed -- Keep the list current and manageable +- **Move completed tasks** from `TODOS.md` to `COMPLETED.md` to keep the TODO list focused +- Keep both lists current and accurate ### Git Workflow Essentials @@ -80,6 +82,16 @@ docs: Update README **For complete details:** See `AgentUsage/git_guide.md` +### Pull Requests + +Use conventional commits format for PR titles: +``` +feat: Add dark mode toggle +fix: Correct timezone bug +``` + +Write a brief description of what the PR does and why. No specific format required. + --- ## When to Use Skills @@ -101,8 +113,15 @@ docs: Update README - **Before creating pyproject.toml** โ†’ Use skill: `uv-package-manager` - **When managing Python dependencies** โ†’ Use skill: `uv-package-manager` +### Authentication +- **When adding sign-in to a Grove app** โ†’ Use skill: `heartwood-auth` +- **When protecting admin routes** โ†’ Use skill: `heartwood-auth` +- **When validating user sessions** โ†’ Use skill: `heartwood-auth` +- **When integrating with Heartwood (GroveAuth)** โ†’ Use skill: `heartwood-auth` + ### Version Control - **Before making a git commit** โ†’ Use skill: `git-workflows` +- **Before creating a pull request** โ†’ Use skill: `git-workflows` - **When initializing a new repo** โ†’ Use skill: `git-workflows` - **For git workflow and branching** โ†’ Use skill: `git-workflows` - **When setting up git hooks** โ†’ Use skill: `git-hooks` @@ -118,6 +137,7 @@ docs: Update README - **For systematic investigation** โ†’ Use skill: `research-strategy` ### Testing +- **When deciding what to test or reviewing test quality** โ†’ Use skill: `grove-testing` - **Before writing Python tests** โ†’ Use skill: `python-testing` - **Before writing JavaScript/TypeScript tests** โ†’ Use skill: `javascript-testing` - **Before writing Go tests** โ†’ Use skill: `go-testing` @@ -141,6 +161,39 @@ docs: Update README - **When building terminal interfaces** โ†’ Use skill: `rich-terminal-output` - **For Rich library patterns** โ†’ Use skill: `rich-terminal-output` +### Grove UI Design +- **When creating or enhancing Grove pages** โ†’ Use skill: `grove-ui-design` +- **When adding decorative nature elements** โ†’ Use skill: `grove-ui-design` +- **When implementing glassmorphism effects** โ†’ Use skill: `grove-ui-design` +- **When working with seasonal themes** โ†’ Use skill: `grove-ui-design` +- **When building navigation patterns** โ†’ Use skill: `grove-ui-design` + +### Grove Documentation +- **When writing help center articles** โ†’ Use skill: `grove-documentation` +- **When drafting specs or technical docs** โ†’ Use skill: `grove-documentation` +- **When writing user-facing text** โ†’ Use skill: `grove-documentation` +- **When writing onboarding, tooltips, or error messages** โ†’ Use skill: `grove-documentation` +- **When reviewing docs for voice consistency** โ†’ Use skill: `grove-documentation` + +### Grove Specifications +- **When creating new technical specifications** โ†’ Use skill: `grove-spec-writing` +- **When reviewing specs for completeness** โ†’ Use skill: `grove-spec-writing` +- **When standardizing spec formatting** โ†’ Use skill: `grove-spec-writing` + +### Museum Documentation +- **When writing documentation meant to be read by Wanderers** โ†’ Use skill: `museum-documentation` +- **When creating "how it works" content for knowledge base** โ†’ Use skill: `museum-documentation` +- **When documenting a codebase or system for curious visitors** โ†’ Use skill: `museum-documentation` +- **When writing elegant, narrative-driven technical explanations** โ†’ Use skill: `museum-documentation` + +### Grove Naming +- **When naming a new service or feature** โ†’ Use skill: `walking-through-the-grove` +- **When finding a Grove-themed name** โ†’ Use skill: `walking-through-the-grove` + +### Package Publishing +- **When publishing to npm** โ†’ Use skill: `npm-publish` +- **Before npm package releases** โ†’ Use skill: `npm-publish` + --- ## Quick Reference @@ -160,12 +213,14 @@ Skills are invoked using the Skill tool. When a situation matches a skill trigge ### Available Skills Reference | Skill | Purpose | |-------|---------| +| `heartwood-auth` | Heartwood (GroveAuth) integration, sign-in, sessions | | `secrets-management` | API keys, credentials, secrets.json | | `api-integration` | External REST API integration | | `database-management` | SQLite, database.py patterns | | `git-workflows` | Commits, branching, conventional commits | | `git-hooks` | Pre-commit hooks setup | | `uv-package-manager` | Python dependencies with UV | +| `grove-testing` | Testing philosophy, what/when to test | | `python-testing` | pytest, fixtures, mocking | | `javascript-testing` | Vitest/Jest testing | | `go-testing` | Go testing patterns | @@ -177,6 +232,12 @@ Skills are invoked using the Skill tool. When a situation matches a skill trigge | `cloudflare-deployment` | Workers, KV, R2, D1 | | `svelte5-development` | Svelte 5 with runes | | `rich-terminal-output` | Terminal UI with Rich | +| `grove-ui-design` | Glassmorphism, seasons, forests, warm UI | +| `grove-documentation` | Grove voice, help articles, user-facing text | +| `grove-spec-writing` | Technical specifications with Grove formatting | +| `museum-documentation` | Elegant, narrative documentation for Wanderers | +| `walking-through-the-grove` | Finding Grove-themed names for new services | +| `npm-publish` | npm package publishing workflow | | `research-strategy` | Systematic research | --- @@ -223,5 +284,5 @@ For in-depth reference beyond what skills provide, see: --- -*Last updated: 2025-12-22* +*Last updated: 2026-01-22* *Model: Claude Opus 4.5* From 5f2795befba5520230c4981a01cf834e7e36cb0a Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 22 Jan 2026 22:40:32 +0000 Subject: [PATCH 2/2] chore: ignore BaseProject backup directories --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d9cb5d6..d33a1e3 100644 --- a/.gitignore +++ b/.gitignore @@ -61,6 +61,7 @@ dmypy.json # Project-specific .shutter/ # User config directory (when testing locally) +.baseproject-backup-*/ # BaseProject update backups # OS .DS_Store