- Treat this file as the maintained repo guide.
CLAUDE.mdis a symlink to this file for Claude Code compatibility. - No repo-local
opencode.json,.opencode/,.cursor/rules/,.cursorrules, or.github/copilot-instructions.mdis present. - For any visible UI/design change, read
DESIGN.mdfirst; implementation tokens live insrc/styles/app/**andsrc/styles/content/**. - Theme provenance and third-party acknowledgements are maintained in
NOTICE.md.
- Base is the default Bear-compatible theme; bundled optional overrides live under
public/themes/. - Every newly bundled theme must add or update its own
NOTICE.mdentry in the same change, including the upstream project URL, author or copyright holder, license and license URL, and whether the implementation is inspired by or adapted from the upstream work. - Also update the README theme credits when a bundled theme is added or its provenance changes.
- Do not copy upstream theme code unless its license compatibility and notice requirements have been reviewed. Distinguish visual inspiration from source adaptation accurately.
- Runtime/tooling: Node
v22,pnpm@11.6.0, Astro^6.4.6SSR, Tailwind CSS v4 via@tailwindcss/vite, ESLint^10.4.1with Antfu + Astro + formatter rules. - Install/dev/build:
pnpm install,pnpm devorpnpm start(astro dev),pnpm build,pnpm preview. - Local checks:
pnpm lint,pnpm typecheck, andpnpm test; usepnpm lint:fixfor auto-fix,pnpm eslint <path>for focused lint, andpnpm vitest run <test-file>for a focused test. postinstallinstallssimple-git-hookswhen.gitexists; pre-commit runslint-stagedwitheslint --fix.- CI does not validate app behavior:
docker.ymlonly builds/pushes the GHCR image, andsync.ymlonly syncs forks from upstream.
- Small code change:
pnpm eslint <changed-file>,pnpm typecheck, andpnpm test; runpnpm lintif scope widened. - UI or route change:
pnpm lint,pnpm build, then preview/manual check. - Feed/SEO/sitemap changes: manually verify
/rss.xml,/rss.json,/sitemap.xml, and relevant canonical/meta output in preview. - Telegram parsing or proxy changes: verify home, one
/posts/[id]page, RSS output, and a/static/...asset path. - Build config or adapter changes must finish with
pnpm build.
src/pages/contains Astro pages and API-style routes;src/pages/index.astrois intentionally thin and callsgetChannelInfo().src/layouts/BaseLayout.astrowires global CSS,astro-seo, the site header/navigation, RSS links,HEADER_INJECT, andFOOTER_INJECT.src/middleware.tssetsSITE_URL/RSS_URLlocals, handles legacy#tagsearch rewrites, and adds speculation/cache headers.- Telegram fetching/parsing belongs in
src/lib/telegram/**; request caching usesocachewith 5 min max age, SWR enabled, and 1 hour stale max age. - Shared env helpers are in
src/lib/env.ts; runtimeprocess.envwins over build-timeimport.meta.env, and they do not readAstro.locals.runtime.env. - Static proxy logic is shared in
src/lib/static-proxy.ts; both Astro routesrc/pages/static/[...url].tsand Vercel Edge Functionapi/static/index.tsuse it, with/static/:path*rewritten byvercel.json. - Do not broaden the static proxy target whitelist unless the task explicitly changes the security model.
- Keep shared domain interfaces in
src/types.ts; there are no TS path aliases, so use relative imports.
CHANNELis required server-side; missing it throws during Telegram fetch.TELEGRAM_HOSTdefaults in code totelegram.me;.env.exampleusestelegram.dogas an override example.STATIC_PROXYdefaults to/static/only when unset; set it to an empty string for direct Telegram asset URLs.astro.config.mjsselects adapters for Vercel, Cloudflare Workers, Netlify, Node standalone, and EdgeOne;SERVER_ADAPTERoverrides auto-detection, and Cloudflare Pages is explicitly rejected.- EdgeOne is detected from std-env's
edgeone_pagesprovider or platform-providedEDGEONE_PROJECT_ID/EO_MAKERS;DOCKER=truechanges Vite SSRnoExternalbehavior. - If env behavior changes, update
.env.exampleand README docs together.
- Server-rendered HTML is the default; keep browser JS near zero. Telegram comments are the deliberate exception.
- API-style routes must return
Response/Response.json, not Express-like objects. - Follow ESLint formatting: 2 spaces, LF, UTF-8, single quotes, usually no semicolons; let
pnpm lint:fixsettle import order. - Preserve local naming: Astro components and layouts use
PascalCase.astro; pages follow Astro route syntax. - External Telegram HTML must be sanitized via
src/lib/sanitize.tsbeforeset:html; config injections inBaseLayout.astroare the only intentional raw HTML path. - Design changes should preserve the content-first Base contract from
DESIGN.md; Sepia is an optional warm-paper override, not the default. Avoid card-heavy redesigns unless explicitly requested.
Read-only dependency source repositories are available under
.slim/clonedeps/repos/ for inspection. Do not edit these clones.
.slim/clonedeps/repos/HermanMartinus__bearblog/-HermanMartinus/bearblogata6cf650886d11461dd1839d02020ca0aee0fee67; reference for the visitor DOM and default Bear theme contract..slim/clonedeps/repos/panr__hugo-theme-terminal/-panr/hugo-theme-terminalat4acd067c48195ac503541ba75f9259c7158d3792; reference for Terminal CSS and template structure..slim/clonedeps/repos/miantiao-me__astro-aria/-miantiao-me/astro-ariaat15c6eb8143ac55f9ba8d925b43f973ceef046980; reference for Aria styling and Astro component composition.