pensieve-patterns

Reusable patterns from the Pensieve AI chat application.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "pensieve-patterns" with this command: npx skills add magnusrodseth/dotfiles/magnusrodseth-dotfiles-pensieve-patterns

Pensieve Patterns

Reusable patterns from the Pensieve AI chat application.

  1. GitHub Contents API for Note Search

Fetch markdown files from a private GitHub repo without cloning:

// lib/github/api.ts const GITHUB_API_BASE = "https://api.github.com";

async function fetchWithAuth(url: string): Promise<Response> { const token = process.env.GITHUB_TOKEN; const headers: HeadersInit = { Accept: "application/vnd.github+json", "X-GitHub-Api-Version": "2022-11-28", }; if (token) headers.Authorization = Bearer ${token}; return fetch(url, { headers, cache: "no-store" }); }

async function listDirectoryContents(owner: string, repo: string, path = "", branch = "main") { const encodedPath = path ? /${encodeURIComponent(path)} : ""; const url = ${GITHUB_API_BASE}/repos/${owner}/${repo}/contents${encodedPath}?ref=${branch}; const response = await fetchWithAuth(url); if (!response.ok) throw new Error(GitHub API error: ${response.status}); return response.json(); }

// Recursively fetch all .md files export async function getMarkdownFiles(): Promise<{ path: string; title: string }[]> { const repoPath = process.env.GITHUB_REPO; // "owner/repo" const [owner, repo] = repoPath!.split("/"); return getAllMarkdownFilesRecursive(owner, repo); }

  1. @ Mention Popup with Fuzzy Search

Custom popup positioned above the @ symbol:

// Key features: // - Positioned above @ using caret coordinates calculation // - Fuzzy search with fuse.js // - Keyboard navigation (arrows, enter, escape) // - Backspace on empty closes popup and removes @

interface NoteMentionPopupProps { notes: Note[]; onSelect: (note: Note) => void; onClose: () => void; onBackspaceEmpty: () => void; // Remove @ and close inputRef: RefObject<HTMLTextAreaElement>; text: string; cursorPosition: number; }

// Position calculation const getCaretCoordinates = (element: HTMLTextAreaElement, position: number) => { // Create mirror div, copy styles, measure span position // Returns { top, left } relative to textarea };

  1. Shimmer Loading Indicator

Replace spinners with animated shimmer text:

// components/ai-elements/thinking-indicator.tsx import { Shimmer } from "./shimmer"; import { BrainIcon } from "lucide-react";

export function ThinkingIndicator({ message = "Thinking..." }) { return ( <div className="flex items-center gap-2 text-muted-foreground text-sm py-2"> <BrainIcon className="size-4 animate-pulse" /> <Shimmer duration={1.5}>{message}</Shimmer> </div> ); }

// Usage in chat {status === "submitted" && <ThinkingIndicator />}

  1. Dark Mode Only Setup

Force dark mode in Next.js:

// app/layout.tsx <html lang="en" className="dark">

// globals.css - define .dark selector with CSS variables .dark { --background: oklch(0.2478 0 0); --foreground: oklch(0.9851 0 0); // ... other variables }

  1. PWA Icons from Single Source

Generate all icons from one source image:

Using macOS sips

sips -z 512 512 logo.png --out icon-512.png sips -z 192 192 logo.png --out icon-192.png sips -z 180 180 logo.png --out apple-touch-icon.png

Favicon with ImageMagick

sips -z 32 32 logo.png --out favicon-32.png sips -z 16 16 logo.png --out favicon-16.png magick favicon-16.png favicon-32.png favicon.ico

Place in:

  • /public/

  • icon-192.png, icon-512.png, apple-touch-icon.png, logo.png

  • /src/app/

  • favicon.ico (Next.js App Router convention)

  1. Vercel Env Vars from .env.local

Push local env to Vercel production:

Link project

vercel link

Add each variable

source .env.local echo "$SESSION_SECRET" | vercel env add SESSION_SECRET production echo "$GITHUB_TOKEN" | vercel env add GITHUB_TOKEN production

... repeat for each var

Update existing

vercel env rm VAR_NAME production -y echo "$NEW_VALUE" | vercel env add VAR_NAME production

Verify

vercel env ls

  1. AI SDK 6 Chat with Tools

// app/api/chat/route.ts import { streamText, tool } from "ai"; import { anthropic } from "@ai-sdk/anthropic";

const vaultTools = { search: tool({ description: "Search vault for content", inputSchema: z.object({ query: z.string() }), execute: async ({ query }) => searchVault(query), }), };

export async function POST(req: Request) { const { messages } = await req.json(); const result = streamText({ model: anthropic("claude-sonnet-4-20250514"), messages: await convertToModelMessages(messages), tools: vaultTools, stopWhen: stepCountIs(5), }); return result.toUIMessageStreamResponse({ sendReasoning: true }); }

  1. Dexie.js for Client-Side Sessions

// lib/db/dexie.ts const db = new Dexie("Pensieve"); db.version(1).stores({ sessions: "id, createdAt, updatedAt", messages: "id, sessionId, createdAt", });

// lib/db/hooks.ts export function useSessions() { return useLiveQuery(() => db.sessions.orderBy("updatedAt").reverse().toArray()); }

export async function saveMessage(sessionId: string, message: Message) { await db.messages.add({ ...message, id: nanoid(), sessionId, createdAt: new Date() }); await db.sessions.update(sessionId, { updatedAt: new Date() }); }

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

vercel-react-best-practices

No summary provided by upstream source.

Repository SourceNeeds Review
General

web-design-guidelines

No summary provided by upstream source.

Repository SourceNeeds Review
General

conductor-setup

No summary provided by upstream source.

Repository SourceNeeds Review