Skip to main content
← All projects
Active development

Grove

A file-first framework for curated directories and structured knowledge.

2026–Present · Astro · TypeScript · MIT

The withgrove.dev homepage, with a diagram of one source feeding website, SEO, AI-ready and repository outputs.

What it is

Structured knowledge tends to get entered more than once. The same project ends up described on a website, in a README table, in a spreadsheet, and in a search snippet — each drifting from the others at its own pace.

Grove makes the file the only place that description lives. You keep YAML records, optional Markdown bodies, and taxonomy files in a git repository. One build reads them and writes a static site with search and filters, plus every derived output around it: sitemap.xml, robots.txt, JSON-LD, Open Graph images, JSON datasets, and llms-full.txt for machine readers.

There is no server, no database, and no CMS. A rename or a delete propagates to every output on the next build instead of leaving a dead page behind.

pnpm dlx @grove-dev/cli@latest init my-space
cd my-space
pnpm dev

One record, many outputs

A record is one YAML file at data/records/<slug>.yml, with an optional Markdown body at content/records/<slug>.md. The slug must match the filename.

kind: project
slug: astro
name: Astro
description: A web framework for content-driven sites.
category: frameworks
repoUrl: https://github.com/withastro/astro
stacks: [typescript, go]
platforms: [web]
difficulty: intermediate
codebaseSize: large
bestFor:
  - content sites
  - docs sites
whyListed:
  - Strong content collections model
  - First-class MDX support
caveats:
  - Newer than Next.js; smaller plugin ecosystem

name, slug, and kind are required. Everything else — category, repoUrl, stacks, platforms, difficulty, codebaseSize, bestFor, whyListed, caveats — is optional but drives the filters, the ranking, and the detail page.

From that single file the build emits a detail page, rows in every browse and filter index, a sitemap entry, JSON-LD, an OG card, a JSON dataset entry, and a line in the AI-readable text output. Writing that record once, in one place, is the entire point.

The Grove documentation introduction page.

The documentation runs on Grove's own Starlight theme.

The Grove CLI reference listing its commands.

The CLI reference — everything a maintainer repeats is a command.

Collections carry the editorial judgment

A directory is only as useful as the reasoning behind what is in it. Collections live at data/collections/<slug>.yml and pair a query with the curator's note about it.

slug: top-flutter
kind: curated
title: Top Flutter apps
description: Hand-picked Flutter projects demonstrating strong engineering
query:
  stacks: [flutter]
  categories: [productivity, finance]
  excludeStatuses: [archived]
ranking:
  preset: quality
editorial:
  selectionNote: Re-curated for the 2026 launch
  lastReviewedAt: '2026-04-01'

Query fields are ANDed — a record has to satisfy stacks, categories, licenses, minStars, and the rest at once — while array values match on any. Ranking presets are quality, active, curated, recency, and stars.

The editorial block is the part most publishing tools omit: why these entries, chosen on what basis, last checked when.

Staleness is computed, not remembered

The hard part of a directory is not publishing it. It is the entry that quietly stopped being true.

grove sync github pulls repository metadata and derives a health block into data/health.ymlstatus, maturity, tier, visibility, cleanupCandidate, staleReason, confidence, and reasons. Status comes from measured facts, not memory:

Status Rule
active Pushed within the last 183 days
mature Active, 500+ stars, and a recent release or clear license
stale Last push 183–548 days ago
needs_review Last push 548–730 days ago
inactive Last push more than 730 days ago
archived Marked archived on GitHub
unknown No GitHub metadata available

Three further states — historical, quiet, unavailable — are editor-only, because some entries are deliberately frozen and no heuristic should overwrite that.

grove cleanup turns the derived signals into a human review queue. The machine decides what looks stale; a person still decides what to do about it.

The command surface

Everything a maintainer does repeatedly is a command, so it runs in CI as easily as on a laptop.

Command What it does
grove init Scaffolds a complete space
grove update Takes upstream UI changes without overwriting local edits
grove check Validates sources and rebuilds generated outputs
grove sync github Refreshes repository metadata
grove sync contributors Refreshes community metadata
grove cleanup Writes the human review queue
grove import <github-url> Imports an existing list out of a README
grove audit Runs Lighthouse against the configured pages
grove readme generate Updates the generated sections of the README

grove import matters more than it looks: most of these sites start life as a hand-maintained Markdown list, and the first job is getting that list into records without retyping it.

Packages, and the UI you own

Package What it owns
@grove-dev/core Config, schemas, validation, importers, taxonomy, collections, health, sitemap, AI outputs, the data build pipeline
@grove-dev/cli The grove binary: scaffolding, checks, sync, cleanup, imports, audits, README generation
@grove-dev/astro The Astro integration and server view-models
@grove-dev/starlight The Starlight theme the Grove documentation itself runs on

The four are versioned in lockstep. The UI is deliberately not among them.

Pages and components ship as a shadcn registry. grove init installs them into the generated project as source, and records a hash for every file it wrote. grove update later diffs upstream against those hashes, so it can bring in new UI without ever overwriting a file you changed. Customising a site never means forking the pipeline.