Planter Content
This repository contains the blog posts, documentation, series, newsletters,
and other content for planter.garden. Content is
Markdown with YAML frontmatter; the website is statically generated from it
by the Jaspr site in the main planter
repo.
Structure
planter_content/
├── blog/ # Growing guide posts (one folder or .md file per post)
├── docs/ # Documentation, organized by section folder
├── series/ # Series landing pages
├── author/ # Author bio pages
├── newsletters/ # Newsletter archive
├── eula.md # Legal pages
├── privacy.md
└── .github/
└── workflows/
└── trigger-jaspr-build.yml # Triggers the website rebuild on push
How publishing works
Push to main and the website rebuilds itself — no other steps:
- A push triggers a content-only build of the website (the Flutter app part is cached, only the static site is rebuilt).
- planter.garden is live with your changes in about 5 minutes.
-
preview.planter.garden rebuilds at the same time and additionally shows
all
draft: truecontent — send authors there to review drafts in full site context.
You can also skip this repo entirely and use the CMS at planter.garden/admin — it edits this repository through the GitHub API and publishes the same way.
Local development, from zero
Run the real website locally against your working copy of the content, so you can preview docs/blog changes before pushing.
1. Prerequisites
-
git, with SSH access to the PlanterApp GitHub org (the site build
depends on the private
planter_corepackage via SSH). Test with:ssh -T git@github.com -
Flutter SDK (the site's Dart packages require it — plain Dart isn't
enough): https://docs.flutter.dev/get-started/install, then confirm
flutter --versionworks.
2. Clone both repos side by side
The site expects planter_content to be a sibling of the planter repo:
cd ~/development # or wherever you keep repos
git clone git@github.com:PlanterApp/planter.git # skip if you have it
git clone git@github.com:PlanterApp/planter_content.git
3. Link the content into the site
cd planter/web_jaspr
rm -rf content # remove any existing checkout
ln -s ../../planter_content content
(../../planter_content resolves from inside web_jaspr/, which is why the
repos must be siblings.)
4. Install the Jaspr CLI
dart pub global activate jaspr_cli
Make sure ~/.pub-cache/bin is on your PATH (the activate command prints a
warning with instructions if it isn't).
5. One-time package setup
The site depends on the shared planter_models package, which needs its code
generated once (and again whenever its models change):
cd planter/packages/planter_models
dart pub get
dart run build_runner build --delete-conflicting-outputs
6. Run the dev server
cd planter/web_jaspr
dart pub get
jaspr serve
The first build takes a few minutes (later ones are incremental). Then open:
- http://localhost:8080/docs — documentation
- http://localhost:8080/blog — growing guide
-
Plant pages use a data snapshot checked into
web_jaspr/data/— possibly stale, but fine for content work.
7. The editing loop
- Edit Markdown in your
planter_contentcheckout. - Reload the page — the dev server re-reads content per request.
-
If a change stubbornly doesn't appear (file watching through the symlink
is imperfect), restart
jaspr serve. -
draft: truecontent is always visible in local dev, exactly like on the preview site. -
When it looks right: commit, push to
main(or open a PR for review), and it's live in ~5 minutes.
Content format
Blog post (blog/<slug>/index.md)
---
title: "Post Title"
description: "Brief description for SEO"
date: 2026-01-15T09:00:00.000Z
author: Full Name
tags: ["Compost", "Soil Health"]
series: ["Herbs"]
plants: ["Basil", "Mint"] # links the post to plant pages + app feeds
cover:
image: "https://ucarecdn.com/<uuid>/"
alt: "Image description"
draft: true # remove (or set false) to publish
---
Content goes here...
Referencing a series that doesn't have a landing page yet? Publishing through
the CMS creates one automatically; when editing here directly, add
series/<slug>/index.md yourself (copy an existing one).
Doc page (docs/<section>/<slug>/index.md)
---
title: "How do I do the thing?"
description: "Shown in search results and section overviews"
weight: 210 # sort order within the section (lower = higher)
toc: true # show the on-page table of contents
---
The folder structure is the site structure: docs/plants/add-plants/index.md
is served at /docs/plants/add-plants. Each section folder has an index.md
(the section overview) whose title and weight drive the sidebar
navigation.
Components available in Markdown
<Notice type="tip">Markdown works **inside** notices.</Notice> # tip | info | warning | note
<YouTube id="VIDEO_ID" />
<Mdi name="sort" label="Sort icon" /> # inline Material Design Icon
<Caption text="Source: ..." /> # small muted caption (e.g. under tables)
<Search /> # docs search box (docs pages only)

Images should be hosted on UploadCare (the CMS uploads there automatically); portrait screenshots are automatically constrained so they don't dominate the page.
Contributing
-
Branch (or edit
maindirectly for trivial fixes — pushes tomaindeploy). -
Add or edit content; preview locally or rely on
draft: true+ the preview site. - PR for anything that wants review; merge publishes it.