The discriminated Resource union — every kind, every field, every default. The schema grove validate and grove generate work against.
Grove V1 ships a discriminated Resource union with three concrete
shapes, bound 1:1 to the three blueprints:
kind: 'project'—project-directoryblueprintkind: 'resource'—resource-hubblueprintkind: 'entity'—ecosystem-mapblueprint
Every record inherits a shared base and adds a kind-specific
extension. The CLI rejects records whose kind does not match the
space’s blueprint in grove.config.ts.
Convention: one file per record, named <slug>.yml. The file
name is the canonical slug. The build pipeline enforces
slug === filename-without-extension.
The shared base
Section titled “The shared base”Every record, regardless of kind, carries these fields:
Type: string (required, min 1)
Convention: kebab-case, matching the filename
The unique identifier. Used as the URL, the cross-reference key
(related[], parent), and the in-page anchor.
description
Section titled “description”Type: string · Default: ""
A short, single-sentence summary. Shown in list cards, search
snippets, and llms.txt. Aim for under 200 characters; the
renderer truncates with an ellipsis after that.
category
Section titled “category”Type: string (required, min 1) · Default: "uncategorized"
A single category. Configure the allowed set in
data/taxonomy/categories.yml (or by convention in your space).
Type: string[] · Default: []
Free-form labels. Normalize by convention (lowercase, kebab-case) so cross-record searches work.
Type: Record<string, string> (URL values) · Default: {}
A map of named links. Recognized keys: github, website, docs,
source. Additional keys are allowed (catchall) for project-specific
links.
content
Section titled “content”Type: string (path) · Default: undefined
Optional path to a Markdown body for the record, relative to
paths.bodiesDir (default content/records/). The renderer
embeds the body on the detail page.
source
Section titled “source”Type: object · Default: { type: "manual" }
Provenance. Useful for distinguishing hand-authored records from imported ones.
| Field | Type | Description |
|---|---|---|
type |
"manual" | "github-topic" | "awesome-list" | "submit" | "import" |
How the record was created |
file |
string |
Original file path (for imports) |
url |
string |
Original source URL |
provider |
string |
Provider name (e.g. github) |
owner |
string |
GitHub owner (if applicable) |
repo |
string |
GitHub repo name (if applicable) |
curation
Section titled “curation”Type: object · Default: { reviewed: false, labels: [], lenses: [] }
Curator metadata on the record itself.
| Field | Type | Default | Description |
|---|---|---|---|
reviewed |
boolean |
false |
Has a human reviewed this record? |
reviewedBy |
string |
— | Curator handle |
reviewedAt |
string |
— | ISO timestamp |
notes |
string |
— | Free-form curator notes |
labels |
Array<"new" | "hot" | "mature" | "featured"> |
[] |
Curator-applied labels (separate from auto-derived health.tier) |
lenses |
string[] |
[] |
Lens names this record should appear in (e.g. hot, new, mature) |
scores
Section titled “scores”Type: object · Default: {}
Optional 0-100 scores for the record across multiple dimensions. Adapters and the home page can use these to rank and filter.
| Field | Type | Range | Description |
|---|---|---|---|
activity |
number |
0-100 | Recency and frequency of commits |
maturity |
number |
0-100 | Stability and production-readiness |
learning |
number |
0-100 | Quality of docs, examples, and onboarding |
contribution |
number |
0-100 | Openness to outside contributions |
docs |
number |
0-100 | Quality of documentation |
overall |
number |
0-100 | Composite score |
visibility
Section titled “visibility”Type: "highlight" \| "keep" \| "needs_review" \| "hide" \| "remove" \| "historical" · Default: "keep"
Effective visibility after any decisions.yml override. For
project records, the canonical signal lives in
health.visibility; for resource and entity records, this
top-level visibility is the source of truth.
ProjectRecord (kind: project)
Section titled “ProjectRecord (kind: project)”For the project-directory blueprint. The full record with
project-specific fields:
kind: projectslug: cal-comname: Cal.comdescription: Open-source scheduling infrastructure for teams and platforms.category: productivitytags: [scheduling, calendar, saas]links: github: https://github.com/calcom/cal.com website: https://cal.comrepoUrl: https://github.com/calcom/cal.comlogoUrl: https://example.com/calcom-logo.pngstack: Next.jsstacks: [Next.js, TypeScript, Prisma, tRPC]platforms: [Web, Self-hosted]projectType: production # real-app | production | reference | library | tool | demo | template | historicaldifficulty: intermediate # beginner | intermediate | advancedcodebaseSize: large # small | medium | large | hugebestFor: - Adding scheduling to SaaS products - Replacing Calendly with a self-hostable alternativewhyListed: - Active, well-maintained open-source projectcaveats: - Requires Postgres for self-hosted setupsdistribution: channels: - { type: docker, platform: linux, label: "Docker image" } - { type: website, url: https://cal.com, verified: true }github: repository: full_name: calcom/cal.com stargazers_count: 32000 pushed_at: "2024-09-14T..." sync: syncedAt: "2024-09-14T..." source: apihealth: status: active # active | mature | stale | inactive | archived | unknown | historical | needs_review | quiet | unavailable maturity: mature # experimental | useful | mature | unknown tier: curated # curated | listed | experimental | hidden visibility: keep # (see Visibility enum above) cleanupCandidate: false confidence: high # low | medium | high reasons: []Project-specific fields
Section titled “Project-specific fields”| Field | Type | Description |
|---|---|---|
name |
string (required) |
Human-readable name. Shown in cards and headings. |
projectType |
enum | One of real-app, production, reference, library, tool, demo, template, historical |
stack |
string |
The single primary stack piece (e.g. Next.js) |
stacks |
string[] |
Full stack list |
platforms |
string[] |
Web, Self-hosted, CLI, iOS, Android, etc. |
difficulty |
enum | beginner | intermediate | advanced |
codebaseSize |
enum | small | medium | large | huge |
repoUrl |
string (URL) |
Canonical repo URL. Preferred by grove sync github over links.github. |
logoUrl |
string (URL) |
Optional logo/avatar. Falls back to the GitHub owner avatar (for github.com repoUrl) or initials. |
bestFor |
string[] |
Short bullets on what the project is good for |
whyListed |
string[] |
Curator note: why this record is included |
caveats |
string[] |
Curator note: things to be aware of |
distribution.channels |
array | Where the project ships: docker, npm, pypi, website, etc. |
github.repository |
object | Live metadata from grove sync github (do not edit by hand) |
health |
object | Auto-derived + curator-overridden health block |
The health block
Section titled “The health block”The health block is the auto-derived signal of how fresh and
relevant the record is. It is populated by grove sync github and
can be overridden by curator decisions in data/decisions.yml.
| Field | Type | Description |
|---|---|---|
status |
enum | active (commit ≤ 180d), quiet (≤ 365d), stale (≤ 730d), inactive (> 730d), archived, unavailable, unknown, historical, needs_review |
maturity |
enum | experimental, useful, mature, unknown |
tier |
enum | curated (≥ 500★ or ≥ 4 active months), listed (≥ 50★), experimental (else), hidden (archived/unavailable) |
visibility |
enum | keep (tier=curated/listed/experimental), hide (tier=hidden) — overridden by decisions.yml |
cleanupCandidate |
boolean |
true for stale, archived, inactive, unavailable |
staleReason |
string | null |
Machine-readable reason: no_commits_365_days, no_commits_24_months, github_archived, github_unavailable |
confidence |
enum | low, medium, high — curator confidence in the signal |
reasons |
string[] |
Human-readable reasons for the current state |
Health is a review signal, not a final ranking. The
cleanup-stale-records.yml workflow surfaces records with
cleanupCandidate: true for human review; the curator decides
whether to keep, hide, mark historical, or remove.
ResourceRecord (kind: resource)
Section titled “ResourceRecord (kind: resource)”For the resource-hub blueprint. For curating pieces of content:
kind: resourceslug: choosing-a-databasetitle: How to choose a database for your side projecttype: guide # guide | comparison | link | explainer | tool | video | article | course | book | podcast | othertopic: databases # the high-level topicdescription: A practical decision tree for picking a database.category: engineeringtags: [database, postgresql, sqlite]links: website: https://example.com/db-chooserrelated: # slugs of related resources - postgres-vs-sqlite - understanding-indexespublishedAt: "2024-08-01"author: Jane DoeResource-specific fields
Section titled “Resource-specific fields”| Field | Type | Description |
|---|---|---|
title |
string (required) |
The resource’s title |
type |
enum (required) | guide | comparison | link | explainer | tool | video | article | course | book | podcast | other |
topic |
string (required) |
High-level topic (e.g. databases, deployment, career) |
related |
string[] |
Slugs of related resources |
publishedAt |
string (date) |
Publication date |
author |
string |
Author name |
EntityRecord (kind: entity)
Section titled “EntityRecord (kind: entity)”For the ecosystem-map blueprint. For curating organizations
and people:
kind: entityslug: mn-ai-communityname: Mongolia AI Communitytype: community # company | organization | community | school | university | research-lab | agency | service | product | person | otherdescription: A community of AI practitioners in Mongolia.category: communitytags: [ai, mongolia, community]founded: "2023-04-15"location: Ulaanbaatar, Mongoliamembers: 250parent: mn-tech-scene # slug of a parent entitylinks: website: https://example.com/mn-aiEntity-specific fields
Section titled “Entity-specific fields”| Field | Type | Description |
|---|---|---|
name |
string (required) |
The entity’s name |
type |
enum (required) | company | organization | community | school | university | research-lab | agency | service | product | person | other |
founded |
string (date) |
Founding date (ISO) |
location |
string |
Free-form location (city, country, “Remote”, etc.) |
members |
number (int ≥ 0) |
Member count, if applicable |
parent |
string |
Slug of a parent entity (for sub-communities) |
Related docs
Section titled “Related docs”- Blueprints — which
kindgoes with which blueprint. - grove.config.ts — site config.
- CLI —
grove validateandgrove generateuse this schema.