Guidance for AI agents (and humans) working in the LibCard repository. LibCard is a free, open-source, self-hostable link-in-bio page + virtual business card, built as a static site and deployed to GitHub Pages.
This repo uses Conventional Commits. Every commit message must follow:
<type>(<optional scope>): <short, imperative summary>
<optional body explaining what & why>
<optional footer(s)>
Types used here:
| Type | When to use |
|---|---|
feat |
A new feature for users (a new card section, theme, QR option, …) |
fix |
A bug fix |
docs |
Documentation only (README, this file, docs/explorations/**) |
style |
Formatting / whitespace; no logic change |
refactor |
Code change that neither fixes a bug nor adds a feature |
perf |
Performance improvement |
test |
Adding or correcting tests |
build |
Build system, dependencies, or tooling (package.json, lockfile, Astro/Tailwind config) |
ci |
CI/workflow changes (.github/workflows/**) |
chore |
Repo housekeeping that doesn't fit above (scaffolding, .gitignore, skills) |
Conventions:
- Summary in the imperative mood ("add", not "added"/"adds"), lowercase, no trailing period, ideally ≤ 72 chars.
- Use a scope when it sharpens intent — e.g.
docs(exploration): …,feat(vcard): …,build(deps): …. - Breaking changes: add
!after the type/scope (feat!: …) and/or aBREAKING CHANGE:footer.
Examples from this repo:
docs(exploration): explore LibCard architecture, tooling & new-user workflow
docs(exploration): standardize on pnpm as the package manager
feat(vcard): generate contact.vcf at build time
build(deps): add Tailwind CSS v4 via @tailwindcss/vite
- Package manager: pnpm. Use
pnpmfor everything —pnpm install,pnpm build,pnpm run setup. Commitpnpm-lock.yaml; never commitpackage-lock.jsonoryarn.lock. (Note: invoke project scripts namedsetupaspnpm run setup— barepnpm setupis pnpm's own built-in.)
- Explorations / design docs live in
docs/explorations/and follow theNNNN_[_]_TITLE.mdnaming convention (the[_]flips to[x]once the recommendations are implemented). Start design work by reading the latest exploration. Commit docs with thedocs(exploration): …scope. - Keep the README in sync with the actual flow — both the quick-start
(getting set up) and the "Updating your card" section /
docs/UPGRADING.md(staying current). A change to either flow should update its docs in the same PR. - Content vs. engine boundary. A user's files are sacred:
libcard.config.yaml, everything inpublic/, and any theme they authored. Everything else —src/**,scripts/**, build config,.github/workflows/**, and the built-inthemes/*.yaml— is the replaceable engine thatpnpm run updatesyncs from upstream. When updating a user's card, never overwrite their content; the build regenerates derived files (libcard.schema.json,src/data/themes.json,src/styles/themes.gen.css,themes/theme.schema.json) so don't hand-edit those. - The landing page is just a card — every affordance is a toggle. The deployed
demo site is the maintainer's own
libcard.config.yaml, not a separate marketing build. So there is no such thing as a "landing-page-only" feature: anything the demo shows off (the theme randomizer, switcher, "Powered by LibCard" badge, ★-star buttons, About/FAQ content blocks, card mode) is an ordinary config flag any user can switch on or off. Acceptance test for any new "landing page" idea: can a user reproduce it by config alone? If not, it doesn't ship. Don't add bespoke marketing components or a second/examples/landingconfig — extend the shared feature set instead. Background:docs/explorations/0008_[_]_LANDING_PAGE_AND_VIRAL_LOOP.md.