Files
Lucas WintherandClaude Opus 5.5 5491230807 docs(agents): work-k2 is the visual truth for /work/
Owner asked for the rules file change on 2026-11-12.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 10:56:29 +01:00

6.7 KiB

portfolio-next

The next lucaswinther.info: a two-gate personal site (work / off the clock). Bun 1.3, TypeScript, Astro (static) with React islands, one Docker container that polls a separate content repo and rebuilds (see docs/DECISIONS.md). Sister repo with the same stack and conventions: commission-compass (Gitea, lucasw89/); copy its patterns before inventing new ones.

AGENTS.md is the single source of truth for agents here. CLAUDE.md and GEMINI.md only point here. Deeper context on demand: docs/ARCHITECTURE.md, docs/DECISIONS.md, docs/TODO.md.

Commands

Verified in this repo (see docs/PERMISSIONS.md):

  • bun install --frozen-lockfile — install from the lockfile
  • bun run typecheck — tsc --noEmit
  • bun test — whole suite (bunfig.toml roots it at test/)
  • bun test test/x.test.ts — one file; bun test -t 'name' — tests matching a name
  • bunx playwright test — e2e against a built fixture site on port 4378 (bun run e2e); asks first
  • bun src/cli.ts validate <dir> — check a content dir, list every problem (fixtures: fixtures/content)
  • SOURCES_FIXTURES=fixtures/sources bun src/cli.ts build fixtures/content .tmp/site — render the static site
  • bun src/cli.ts preview .tmp/site [port] — serve a built site (default 4321)
  • docker build -t portfolio-next:local . && scripts/smoke-test.sh portfolio-next:local — image builds and serves fixtures Bun is the runtime and package manager, never Node, npm, pnpm or yarn: bun <file> not node, bun test not jest/vitest, bun install / bun run <script>, bunx not npx. Bun loads .env itself; don't add dotenv. Prefer Bun built-ins (Bun.serve, Bun.file, Bun.$`…`, Bun.YAML). Exception: the site is Astro (built on Vite). bun init's "HTML imports, don't use vite" advice does not apply to it.

Workflow

Required skills: superpowers, impeccable. Check at session start; install if missing. Specs → docs/specs/NNN-slug.md (permanent). Plans → docs/plans/NNN-slug.md while in progress; git rm them before opening a merge request — the spec is the record. (Overrides the superpowers default paths, e.g. docs/superpowers/specs/.)

Anything beyond a trivial fix: brainstorm → spec (sign-off) → plan → TDD → review. TDD means failing test first, watch it fail, minimal code, watch it pass, commit. Tick plan checkboxes as you go so an interrupted session is resumable. Trivial changes (typo, version bump, one-line config): say "trivial, skipping spec" and proceed.

Use impeccable for user-facing UI — craft for new, audit/polish on existing, harden before shipping. Design context: PRODUCT.md, DESIGN.md.

Rules

  • The chosen mockups are the visual source of truth: mockups/nav-d.html (start page), mockups/work-k2.html (/work/, spec 009; built on mockups/tech-r3-c.html, which still sets the rest of the work space: panels, list, side sheet, project pages), mockups/personal-r2-b.html (off the clock). Match them; don't drift towards a generic template. Every other file in mockups/ is a rejected or reference round.
  • docs/inspiration.md records the owner's taste in his own words. Read its principles before any visual change. Hard lines: no loading screens, nothing moves unless the visitor acts, no canvas/game feel, nothing that sells, no purple/blue "AI" gradients.
  • Every project carries an AI level: ai-made | some-ai | by-hand | unknown. Never guess one; unknown stays unknown and is shown as such.
  • Never invent facts about the owner (jobs, dates, life events, opinions). Unknown facts stay out of content, or go in as draft: true; ask the owner. Real work history: extra_info.txt.

Architecture

src/core pure logic shared by build and browser · src/library content loading and validation · src/sources Ghost/Trakt/Hardcover clients and cache · src/site Astro pages, components, layouts, styles · src/runtime build, refresh (poll, rebuild, atomic swap), serve · src/cli.ts entry point · fixtures/ synthetic content and source JSON · e2e/, test/ · deploy/, scripts/ · archive/2021/ old site · mockups/ the approved visual source of truth.

Full picture: docs/ARCHITECTURE.md — read it before your first change in a session. Content format: docs/CONTENT-CONTRACT.md. Deploying: docs/DEPLOY.md.

Non-obvious rules

  • src/core stays pure: no imports from other src/ folders, no Node/Bun APIs, no I/O. The browser bundles it.
  • No network during Astro rendering. Only buildSite fetches (once); pages read the cached sources.json.
  • The real content lives in the separate portfolio-next-content repo. Fixtures here are synthetic; never copy real content in. Tests set SOURCES_FIXTURES=fixtures/sources and never call Ghost, Trakt, Hardcover or Gitea.
  • Filter contract: set data-ai only where ai !== null; elements without it are never hidden by the preference. Never write display: … !important on [data-ai] (it defeats the hide rules).
  • Islands use client:idle when they sit off-screen (sheet, chips); client:visible would never fire.
  • Nothing third-party loads before interaction, except the analytics script. Fonts are @fontsource*.
  • Test imports use explicit .ts extensions.

Boundaries

Never touch: .superpowers/ (local brainstorm sessions, gitignored), extra_info.txt (owner-maintained). Never commit .env, secrets, or credentials. Never force-push, rewrite pushed history, or commit directly to main.

Ask first: new runtime dependencies · deployment, containers or the owner's homelab config · anything destructive (rm -rf, git reset --hard) · work the approved plan does not cover.

If the task turns out much larger than the plan assumed: stop, report, re-plan.

Docs duties

Same commit as the code, not "later":

  • docs/ARCHITECTURE.md — when a module, boundary, or data flow changes.
  • docs/DECISIONS.md — append-only; any choice a future maintainer would reverse-engineer.
  • docs/TODO.md — anything noticed and deliberately not fixed. No TODO comments in source.
  • docs/PERMISSIONS.md — together with .claude/settings.json, .codex/, .gemini/settings.json, in one commit.

Git

Branches: feat|fix|chore/<slug>. Commits: Conventional Commits. Small, each leaving tests green. Merge to main locally, and only when the owner asks and approves. No pull requests.

Done means verified

Do not report success on work you have not run. Before saying done: tests run in this session and seen passing · lint and typecheck clean · matches the approved spec · UI changes rendered and looked at (headless Chrome works: google-chrome --headless=new --no-sandbox --screenshot=out.png --window-size=1440,900 file://$PWD/page.html) · docs duties complete · git status clean and the diff is only what you intended.