This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Palimpsest is a version-aware writing tool with a React-based frontend that visualizes text diffs between article versions. Articles are written in MDX format and stored in the articles/ directory. The frontend renders articles with inline diff highlighting (green insertions, red deletions), a sidebar with outline navigation and version history, and supports Mermaid diagrams via fenced code blocks.
All development commands run from the frontend/ directory:
cd frontend
# Start dev server (port 5173, uses polling for file watching)
npm run dev
# Production build (runs TypeScript check first)
npm run build
# Run all tests (Vitest with jsdom)
npm run test
# Run a single test file
npx vitest run src/hooks/__tests__/useDiff.test.ts
# Run tests in watch mode
npx vitest
# Lint
npm run lint
# Preview production build
npm run previewAll dependencies and development happen in frontend/. The repository root has no package.json — do not create one or run npm install from the root.
frontend/— React + Vite + TypeScript application (all dev commands run here)articles/— Article content directories, each containingmeta.json,article.mdx, andprevious.mdxdocs/— Design specs and implementation plans.superpowers/— Brainstorming artifacts from the superpowers workflow
- Build: Vite with
@vitejs/plugin-react(Oxc-based) and@mdx-js/rollupfor MDX support - Styling: Tailwind CSS v3 + custom CSS in
src/styles/diff.css - Testing: Vitest with jsdom,
@testing-library/react - Diff engine:
diff-match-patchlibrary with semantic cleanup - Diagrams:
mermaidlibrary for rendering diagrams in MDX - MDX runtime:
@mdx-js/mdxfor client-side MDX compilation,@mdx-js/reactfor component provider,remark-gfmfor GitHub Flavored Markdown
The app supports three view modes, each with a different rendering strategy:
-
comparemode:DiffRenderershows a line-level diff with red deletions and green insertions. Each line is independently compiled to MDX via@mdx-js/mdxat runtime. Special block structures (fenced code blocks, tables, lists, blockquotes) are merged across consecutive lines before compilation so they render correctly. A globalcompileCachededuplicates compilation for identical lines. -
newmode:RuntimeMdxcompiles the entire currentarticle.mdxtext into a React component at runtime. Supports full MDX features including GFM tables and Mermaid diagrams. -
oldmode:RuntimeMdxcompiles the entireprevious.mdxtext, same asnewmode but with the previous version.
The MDXProvider (from @mdx-js/react) wraps the app in main.tsx and provides custom components. Currently only a custom <pre> component is registered, which intercepts fenced mermaid code blocks and renders them as <MermaidBlock>.
Each article lives in articles/{id}/ with three files:
meta.json— Title, version, timestamps, version history arrayarticle.mdx— Current version contentprevious.mdx— Previous version for diff comparison
Articles are loaded at runtime via fetch() from the static file server. The publicDir in vite.config.ts is set to ../ (repo root), so articles/ is served at /articles/.
useArticle loads meta + both MDX texts → useDiff(previousText, currentText, true) computes line-level segments via diff-match-patch with semantic cleanup → DiffRenderer renders segments with per-line MDX compilation and animation via useDiffAnimation.
@/ resolves to frontend/src/.
tsconfig.jsonis a project references root pointing totsconfig.app.jsonandtsconfig.node.jsonverbatimModuleSyntax: true— requiresimport typefor type-only importsnoUnusedLocals: trueandnoUnusedParameters: true— unused variables cause build errorserasableSyntaxOnly: true— noenum,namespace, or parameter properties
Custom MDX components live in src/components/. MermaidBlock renders Mermaid diagrams. Fenced mermaid code blocks in MDX are automatically converted to <MermaidBlock> by the MDX pipeline via the custom <pre> component in MdxProvider.
To add a new custom component: create it in src/components/, export from src/components/index.ts, and register in src/mdx-components/MdxProvider.tsx.
- Unit tests for hooks use
renderHookfrom@testing-library/reactwith mockedfetch - Component tests use
render/cleanupfrom@testing-library/react vi.useFakeTimers()is used for testing animation delays inDiffRenderer- Tests for
DiffRendererverify HTML output viacontainer.innerHTMLandcontainer.textContent
DiffRenderercompiles each diff line individually via@mdx-js/mdx— compilation failures fall back to rendering the raw text- Special block structures (fenced code blocks
```, tables|, lists-/1., blockquotes>) are merged across consecutive lines before MDX compilation - Diff animations only trigger in
comparemode;old/newmodes skip animation - The sidebar extracts headings from raw MDX text via regex (
^(#{1,3})\s+(.+)$), not from parsed AST usePolling: truein Vite server config is set for environments where native file watching doesn't work reliablyloadArticleTextguards against the dev server returning HTML fallback pages (checkscontent-typeheader)