| Path | What lives there |
|---|---|
src/ |
The SvelteKit site — landing page, explorer, library, generator |
docs/ |
The documentation, synced with docs.vale.sh |
src/lib/data/ |
Adopters, press, and events — the three files most contributions touch |
script/ |
Data validation and avatar syncing |
pnpm install
pnpm run dev -- --open| Command | What it does |
|---|---|
pnpm run dev |
Development server |
pnpm run build |
Production build |
pnpm run validate |
Check adopters.json, press.json, and events.json |
make configs |
Re-read the adopters' public .vale.ini files into config-stats.json |
make stats |
Count CI use, house rules, CI runs, and downloads into adopter-stats.json (a weekly workflow runs this and opens a pull request) |
make og-adopters |
Re-render the /adopters social card from the data |
pnpm run check |
Type-check with svelte-check |
pnpm run lint |
Prettier and ESLint |
Home page numbers — downloads, stars, backers — are read from the GitHub, Docker
Hub, PyPI, conda-forge, Homebrew, Chocolatey, and Open Collective APIs at build
time (see src/lib/server/stats.ts). Each lookup
falls back to a checked-in value, so a failed request never breaks the build. Set
GITHUB_TOKEN in the build environment to keep the GitHub calls off the 60/hr
per-IP limit.
The docs live at docs.vale.sh, published from GitBook
and synced to docs/ in this repository. The two stay in step
automatically: a commit to docs/ updates the site, and an edit made in GitBook
lands here as a commit.
So you can contribute either way. Editing the Markdown under docs/ and opening
a pull request is the usual route — your PR gets a preview URL as a status check,
so you can see the rendered page before it merges.
Important
Two files are not yours to edit. docs/SUMMARY.md is the table of contents and
is generated by GitBook, so change the page tree in GitBook instead.
.gitbook.yaml tells the sync that content lives in docs/.
The site used to render these pages itself from src/lib/content. It no longer
does — vale.sh/docs/* redirects to docs.vale.sh (see
static/_redirects).
If your team runs Vale, add an entry to
src/lib/data/adopters.json. Every entry needs a
public link that shows Vale in use — a .vale.ini, a style package, or a
write-up. Entries without one get removed.
{
"name": "Elastic",
"category": "Data & observability",
"context": "Ships an Elastic style guide implemented as Vale rules.",
"url": "https://www.elastic.co/docs/contribute-docs/vale-linter",
"icon": "elastic"
}| Field | Required | Notes |
|---|---|---|
name |
yes | How your team is normally written. |
category |
yes | One of the nine sectors below. |
context |
yes | One sentence, ending in a period, on what Vale does for you. |
url |
yes | https:// link to the public proof. |
icon |
no | A Simple Icons slug, e.g. elastic, gitlab. |
github |
no | GitHub org login, e.g. aiven. Used when there's no icon. |
repo |
no | Where the config lives when url is a write-up: github.com/owner/name or a gitlab.com path. The stats scripts read it. |
Sectors: AI & machine learning, Cloud & infrastructure,
Data & observability, Developer tools, Enterprise software,
Hardware & semiconductors, Open source & communities,
Academia & public sector, Web3 & blockchain. Pick the one a reader would
file the team under, not the one the linted repository happens to be about.
Set either icon or github, not both. Simple Icons doesn't carry every
brand — Microsoft and AWS, for example — so github falls back to your org's
avatar. With neither, the card shows a two-letter monogram.
Note
Don't commit images. The avatar PNGs under static/users/avatars are
fetched from the github field by a maintainer running
node script/adopters.mjs --sync.
The four cards above the marks on the home page each carry one number from a
team's own page. Add an entry to
src/lib/data/stories.json:
{
"name": "Datadog",
"figure": "20,000",
"label": "docs pull requests merged in 2023",
"detail": "From 1,400 contributors, with an on-call writer reviewing over 40 a day.",
"url": "https://www.datadoghq.com/blog/engineering/how-we-use-vale-to-improve-our-documentation-editing-process/"
}name must match an adopter, figure is a bare number such as 20,000 or
200+, and url is the page that states it. The home page shows them all,
so keep the list to four.
Add an entry to src/lib/data/media.json. It
shows in the library:
{
"title": "Prose linting with Vale",
"url": "https://blog.meilisearch.com/prose-linting-with-vale/",
"author": "Maryam Sulemani",
"year": 2023,
"type": "post",
"description": "One or two sentences on what it covers.",
"image": "",
"site": "Meilisearch"
}type is post, talk, or video. image can stay empty; make media
fills it and the description from the page's OpenGraph tags.
Published work and coverage in magazines and newsletters go in src/lib/data/press.json,
which the press page and the "In print" section show:
{
"type": "paper",
"title": "Linting Style and Substance in READMEs",
"outlet": "arXiv",
"author": "Hima Mynampaty et al.",
"year": 2026,
"url": "https://arxiv.org/abs/2603.00331"
}| Field | Required | Notes |
|---|---|---|
type |
yes | book, paper, article (a magazine or news feature; blog posts go in the library), or newsletter. |
title |
yes | The title as published. |
outlet |
yes | Publisher, journal, or preprint server. |
url |
yes | https:// link. |
author |
no | Byline. |
year |
no | Integer. |
subtitle |
no | Books only. |
A link can appear once on the site. If your company blog post is already an
adopter's url, don't add it here too — the validator rejects it.
Add an entry to src/lib/data/events.json:
{
"title": "Social Coworking and Office Hours: Vale and Text Linting",
"host": "rOpenSci",
"date": "2026-08-04",
"time": "01:00–03:00 UTC",
"location": "Online",
"url": "https://ropensci.org/events/coworking-2026-08/"
}| Field | Required | Notes |
|---|---|---|
title |
yes | The event or session title. |
host |
yes | Organizer, e.g. rOpenSci. |
date |
yes | Start date, YYYY-MM-DD. |
location |
yes | Online, or a city. |
url |
yes | https:// link to register or read more. |
endDate |
no | YYYY-MM-DD, for events spanning several days. |
time |
no | Free text, e.g. 01:00–03:00 UTC. |
Finished events don't need removing. The section filters by date at both build and page load, so an event disappears — along with its nav link, and the whole section once nothing is left — as soon as it's over. The validator prints a note for entries that have already passed, so they can be cleared out later.
pnpm run validateThis validates all three files: required fields, known categories and types,
https:// URLs, unique names and links, real Simple Icons slugs, and well-formed
dates. CI runs the same command on every push.
If you have a Vale package or configuration you'd like to share, open a pull
request against the packages
repository.
