9.1 KiB
Project Bifrost — Claude Code Memory
This file is persistent context for every Claude Code session on this repo. Keep it under 200 lines. If something is only relevant to one feature, it does not belong here — put it in
SPEC.mdor a scoped file.
Project
Project Bifrost is Fenja AI's invite-only pilot hub — a private website for pilot participants and Customer Advisory Board members during a ~3–4 month pilot of Fenja's sovereign AI platform. Full product specification lives in SPEC.md. Read it before doing anything substantial; it is the source of truth.
Stack
- Framework: Astro 4+ (server output mode where needed, static elsewhere)
- Language: TypeScript, strict mode
- Styling: Vanilla CSS with design tokens derived from
design/colors_and_type.css— no Tailwind, no CSS-in-JS, no component libraries with baked-in styling - Database: SQLite via
better-sqlite3 - Auth: Custom. Session cookies + bcrypt + signed invite tokens. No third-party auth providers.
- Runtime: Node 22 LTS
- Package manager: pnpm (never npm, never yarn)
- Hosting: Single Hetzner Cloud VPS (CAX11, Helsinki) behind Caddy
Commands
pnpm install # install dependencies
pnpm dev # start dev server on :4321
pnpm build # production build
pnpm preview # preview production build locally
pnpm test # run vitest
pnpm typecheck # tsc --noEmit
pnpm lint # eslint + prettier check
pnpm db:migrate # apply migrations to dev SQLite
pnpm db:seed # seed dev database with test users
Always run pnpm typecheck and pnpm test before claiming a task is done.
File structure
/
├── SPEC.md # product spec (source of truth)
├── CLAUDE.md # this file
├── design/ # design system — authoritative for all visual language
│ ├── SKILL.md # instructions for how to use this design system (read first)
│ ├── README.md # human overview
│ ├── ICONOGRAPHY.md # icon style & usage
│ ├── colors_and_type.css # authoritative colour & type tokens
│ ├── assets/ # logo and brand assets
│ ├── fonts/ # font files
│ ├── preview/, screenshots/, ui_kits/, uploads/ # reference material
├── content/ # markdown content
│ ├── updates/ # YYYY-MM-DD-slug.md progress posts
│ ├── meetings/ # YYYY-MM-DD-slug.md meeting pages
│ └── roadmap.md # single roadmap file
├── src/
│ ├── pages/ # Astro routes
│ ├── components/ # Astro components
│ ├── layouts/ # page layouts
│ ├── styles/
│ │ ├── tokens.css # CSS custom properties — derived from design/colors_and_type.css
│ │ └── global.css # base styles, resets, @font-face declarations
│ ├── lib/
│ │ ├── db.ts # SQLite connection & typed queries
│ │ ├── auth.ts # session + password + invite token helpers
│ │ └── content.ts # markdown collection helpers
│ └── env.d.ts
├── migrations/ # numbered .sql files
├── scripts/ # ops scripts (backup, deploy, seed)
└── public/ # static assets served as-is
├── logo.svg # copied from design/assets/ on first session
└── fonts/ # copied from design/fonts/ on first session
Code standards
- TypeScript strict. No
anywithout a comment explaining why. Preferunknownand narrow. - No runtime dependencies unless asked. Before adding a package, justify it. The current stack is chosen for minimalism — resist padding it.
- SQL is written by hand. No ORM. Queries live in
src/lib/db.tsas typed functions (getUserByEmail(email): User | null, etc.). - Zod schemas for all content collection frontmatter, all form inputs, and all env vars. Parse at boundaries; trust internally.
- Server-only secrets go through
astro:envor a server-onlyenv.tsmodule. Never import secrets into client code — verify this. - Errors in route handlers return proper status codes with minimal JSON. Never leak stack traces to clients.
- Dates are always UTC in the database, rendered in Europe/Copenhagen on the page.
- Accessibility is not optional. Every interactive element keyboard-reachable; every image has
alt; colour contrast meets WCAG AA against tokens fromdesign/colors_and_type.css.
Design principles (from SPEC §6)
The aesthetic is authoritative quietude — academic, editorial, Danish-minimal. The design/ folder is the authoritative source; design/SKILL.md is the entry point for how to use it. Concrete rules that hold unless the design system overrides them:
- No visible borders on cards or sections. Separation = tonal background shift + whitespace.
- No drop shadows. If elevation is needed, use a tonal shift.
- Editorial type scale — headlines are large, body copy has room to breathe, line-height ≥ 1.6 for body.
- Asymmetric layouts preferred over centred ones. Use the 12-column grid deliberately.
- Motion is minimal. Transitions < 200ms, ease-out. No parallax, no auto-play.
- Light mode only for v1.
- All colour, font, and spacing values come from
design/colors_and_type.cssviasrc/styles/tokens.css. Never hardcode hex values, font names, or magic spacing numbers in components — reference tokens. If a token is missing, stop and add it totokens.css(faithful to the design system) before continuing.
First-session tasks (in order)
When Claude Code first opens this project:
- Read
SPEC.mdend to end. - Read
design/SKILL.md— follow its instructions. It is the primary guide for how to use the design system. - Read
design/README.md,design/ICONOGRAPHY.md, anddesign/colors_and_type.css. Skimdesign/preview/,design/screenshots/, anddesign/ui_kits/for reference. - Scaffold the Astro project per the file structure above. Install only what the spec requires.
- Copy logo assets from
design/assets/intopublic/(prefer SVG; keep filenames stable, e.g.public/logo.svg). - Copy fonts from
design/fonts/intopublic/fonts/and set up@font-facedeclarations insrc/styles/global.css. - Create
src/styles/tokens.cssderived fromdesign/colors_and_type.css. Either@importit directly, or re-express its values as CSS custom properties — whicheverdesign/SKILL.mdrecommends. - Build a
/style-guideinternal route that renders: every colour token, every type scale step, spacing scale, buttons, form inputs, cards, iconography, and the logo in context. This is for human review before any real pages are built. - Stop and wait for review.
Do not skip step 9. The visual language needs human approval before pages get built on top of it.
Behavioural preferences
- Plan before coding. For any task larger than a trivial fix, propose a plan first and wait for approval.
- Small, reviewable commits. One logical change per commit. Conventional commit messages (
feat:,fix:,chore:,docs:,refactor:,style:). - Ask before: adding a dependency, changing the database schema, changing anything in
design/, changing this file orSPEC.md, deploying. - Never: commit secrets, commit
.env*files, rungit push --force, modify files insidedesign/(that folder is read-only from the code's perspective — if the design needs to change, updatedesign/directly via a separate deliberate commit). - When uncertain about product intent, check
SPEC.md. If the spec is ambiguous, ask — do not guess. - When uncertain about visual language, re-read
design/SKILL.mdanddesign/colors_and_type.css. If it is still ambiguous, ask. - When blocked by a missing decision, write the options as a short note in
DECISIONS.mdand ask for a ruling. Do not silently pick. - Write state to files for long tasks. If a task spans many steps, keep notes in
progress.mdso a fresh session can pick up.
Out of scope
Read SPEC.md §8. Do not build: email sending, file uploads, rich-text editors, dark mode, mobile app, search, analytics, i18n, 2FA, public pages. If the user asks for one of these, confirm it is a scope change and suggest updating SPEC.md first.
Known gotchas
- better-sqlite3 is native. On Hetzner ARM it must be built for ARM. The deploy script rebuilds it on the server.
- Astro server output mode requires an adapter — use
@astrojs/nodeinstandalonemode. - Signed invite tokens are HMAC-signed, not JWTs. Keep them short and opaque.
- Sessions are HttpOnly, Secure, SameSite=Lax cookies. Never expose session IDs to client JS.
- Font licensing. The fonts in
design/fonts/may be licensed — checkdesign/README.mdanddesign/SKILL.mdfor any usage restrictions before serving them publicly.