No description https://sweetgrass.garden
  • Lua 77.3%
  • Go 7.3%
  • Rust 5.9%
  • Shell 5.5%
  • CSS 1.1%
  • Other 2.8%
Find a file
ffad4960 c22549be92
Some checks failed
Tests / lua-tests (push) Failing after 16s
restore: honest messages distinguish "fresh" from "something wrong"
"No prior snapshot" was doing double duty: it meant both "this is a
fresh garden, nothing to restore, all fine" and "a backup source was
connected but the query returned empty — your data didn't come back."
Same words, wildly different realities.

Now: when _restore_source is set (prior backup detected and
connected), empty results produce display.warn instead of
display.ok. The operator sees something unexpected happened rather
than a silent reassurance. For garden-scoped stacks (which can
legitimately have no snapshot if the stack was added since the last
compost), the message names the specific stack.

The distinction: graciousness without context collapses meaningful
differences. The system already knows whether this is a replant
(source detected) or a first plant (no source) — it just wasn't
using that knowledge to shape the message.
2026-05-28 14:22:12 +00:00
.forgejo/workflows press: PUBLISH_TOKEN, not FORGEJO_TOKEN (reserved-prefix block) 2026-05-16 15:34:22 +00:00
ci builder: deploy CGI requires Bearer auth + image origin validation 2026-05-03 04:33:43 +00:00
garden dns verify: fall back to manager for NS query when local dig/host absent 2026-05-26 23:03:23 +00:00
groundwork dns manifest: explicit record ownership replaces content-pattern inference 2026-05-25 09:24:21 +00:00
keepers Rename stewards → keepers 2026-04-19 01:01:58 +00:00
lua fix: compost snapshots garden-scoped stacks (certs, traefik) 2026-05-27 23:37:57 +00:00
plant docs: stop asserting Hetzner S3 keys are region-scoped — unconfirmed 2026-05-21 20:44:58 +00:00
seeds restore image descriptions in seeds 2026-04-28 23:47:26 +00:00
weeds domains: move per-garden under .gardens/<g>/domains, positional ownership 2026-05-20 22:10:10 +00:00
.dev-keys.example Add --dev flag for installing dev SSH keys 2026-01-16 02:49:34 +00:00
.gitignore domains: move per-garden under .gardens/<g>/domains, positional ownership 2026-05-20 22:10:10 +00:00
.pressignore domains: move per-garden under .gardens/<g>/domains, positional ownership 2026-05-20 22:10:10 +00:00
_BUILDING.md rename: ctx → context throughout Lua 2026-05-09 18:20:54 +00:00
_BYOH.md docs: stop asserting Hetzner S3 keys are region-scoped — unconfirmed 2026-05-21 20:44:58 +00:00
_CONVERGENCE.md plan-groundwork: capture the fourth participant kind 2026-05-22 06:52:48 +00:00
_DIGITALOCEAN.md Seed template: drop combination count, use FQDN, rename clone dir 2026-03-28 03:26:51 +00:00
_GARDEN.md Remove startup framing from docs, fix plant.lua arg parsing 2026-04-12 18:45:26 +00:00
_GOTCHAS.md sync docs to reality 2026-04-28 08:01:53 +00:00
_LEGAL.md move governance documents to rhizome/governance 2026-04-26 05:34:51 +00:00
_MIRRORING.md Mirroring: pull-mirror topology, trust policy, upstream chain 2026-04-25 03:12:02 +00:00
_PLAN-assets.md plan: garden abstraction design + planning doc audit 2026-05-03 18:03:18 +00:00
_PLAN-dns-records.md docs: mark externals slice 4, DNS manifest, walk fix as done 2026-05-25 09:25:32 +00:00
_PLAN-externals.md docs: mark externals slice 4, DNS manifest, walk fix as done 2026-05-25 09:25:32 +00:00
_PLAN-garden-abstraction.md docs: delete _PLAN-capability-deploy.md (work fully landed) 2026-05-15 07:43:05 +00:00
_PLAN-groundwork.md remove dead per-domain media bucket code 2026-05-26 09:50:25 +00:00
_PLAN-kind-inference.md groundwork slice 4: compost honors destroy_on_compost 2026-05-23 22:25:23 +00:00
_PLAN-node-orchestration.md docs: name the operator-as-orchestrator assumption 2026-05-15 08:16:48 +00:00
_PRESS.md Remove startup framing from docs, fix plant.lua arg parsing 2026-04-12 18:45:26 +00:00
_QUICKSTART.md domains: move per-garden under .gardens/<g>/domains, positional ownership 2026-05-20 22:10:10 +00:00
_RECOVERY.md sync docs to reality 2026-04-28 08:01:53 +00:00
_SMELLS.md docs: name the operator-as-orchestrator assumption 2026-05-15 08:16:48 +00:00
_STATE-MODEL.md docs: update _STATE-MODEL stale in-flight references 2026-05-26 10:01:49 +00:00
_TODO.md TODO: note destructive DNS upsert behavior for shared zones 2026-05-26 14:58:00 +00:00
_WELL-KNOWN.md well-known convention, status banner, env export fix 2026-04-09 19:37:28 +00:00
about.md Rewrite index opening, drop stale 7k line count everywhere 2026-03-27 17:59:50 +00:00
config.lua.example tend: split commands into modules, update stale documentation 2026-04-02 04:14:05 +00:00
index.md Fix share preview: deduplicate title, add descriptions 2026-03-27 18:19:31 +00:00
LICENSE.txt Update LICENSE.txt 2026-01-12 06:00:28 +00:00
plant.lua restore: honest messages distinguish "fresh" from "something wrong" 2026-05-28 14:22:12 +00:00
prepare.sh Hetzner default in plant guide + DigitalOcean alternative doc 2026-03-26 05:22:03 +00:00
privacy.md privacy: backup retention split, identity privacy link, policy additions 2026-04-09 01:47:56 +00:00
README.md domains: move per-garden under .gardens/<g>/domains, positional ownership 2026-05-20 22:10:10 +00:00
social-contract.md Update social-contract.md 2026-04-05 00:24:45 +00:00
tend.lua canary: tend subcommand for verifying backup/restore round-trip 2026-05-20 22:22:36 +00:00
test.lua remove dead per-domain media bucket code 2026-05-26 09:50:25 +00:00

Sweetgrass

Community infrastructure you can understand, modify, and share.


What this is

Sweetgrass is a set of tools for planting and tending your own corner of the internet — websites, publishing, email, git hosting, video calls — on small, affordable servers that you and your friends control.

Think of it like a community garden. You bring the seeds (your domain, your writing, your projects). The tools help you plant and tend. The infrastructure takes care of itself most of the time, and when it doesn't, you can read the code and fix it. All of it.

Where we are

We're building this right now. The tools work — we've planted multiple gardens and each planting gets smoother. Every one teaches us something new.

This is a barn raising, not a finished house. If that appeals to you — if you want to build something with people instead of buying something from a company — you're welcome here.

What you get

Three scripts named for what they do:

plant.lua    Create infrastructure from scratch
tend.lua     Deploy, update, backup, maintain
compost.lua  Tear everything down (safely, backups first)

The cycle is: plant, tend, compost, plant. Data survives destruction by default.

When you plant, you get a self-organizing cluster with:

your site ── static, always on
  identity ── passkeys and single sign-on
    git ──── your repos (Forgejo)
      press ── push markdown, get a website
        meet ── video conferencing (Jitsi)
  mail ──── email + webmail (docker-mailserver)

Automatic SSL. Encrypted daily backups. Rolling updates with zero downtime. Self-healing via Docker Swarm. The core stack (static through press) fits on a single small server. A 3-node cluster gives you failover and room for meet.

Two ways in

However you join, the social contract is the same: resilience through interdependence, no extraction, invite-based trust, portability.

Plant your own. Get together with friends. Pick your domains. Set up a few small servers. This is the way sweetgrass is meant to grow — many small gardens tended by the people who use them, sharing improvements through the same tools. See QUICKSTART.md.

Grow in the community garden. If you don't want to manage your own infrastructure, you're welcome in ours. It's free, it's invite-only, and your stuff is yours — you can transplant to your own garden or a friend's whenever you want. See GARDEN.md.

The philosophy

No magic. Every operation is a readable Lua script. No hidden state, no declarative DSLs, no frameworks. Just scripts that do things you could do by hand, reliably.

No lock-in. Your domains transplant between gardens. Your content is markdown files in git repos. Your infrastructure is standard Docker on standard servers. Nothing traps you here.

No extraction. We want you not to pay us. We want you to plant your own garden with friends and share what you grow. The code is AGPL — improve it, share it back. The more gardens, the more resilient every garden becomes.

Boring on purpose. The infrastructure is meant to be dull. Pages are simple and lightweight. Servers quietly do what they're supposed to. The most exciting thing about sweetgrass is that it works and you can understand why.

By planting sweetgrass, you're doing something quietly subversive. You're building infrastructure that's democratic by design and resistant to the patterns that turn tools into platforms and communities into products. It doesn't look like much. That's the point.

How it works

The tools call standard unix utilities — ssh, rsync, curl — plus your cloud provider's CLI (hcloud, doctl, or none for BYOH). Docker Swarm handles orchestration. We picked Swarm over Kubernetes because you can understand Swarm in an afternoon.

plant.lua              Create and configure infrastructure
tend.lua               Deploy, update, backup, maintain
lua/compost.lua        Full teardown (backups first)

lua/deploy/            Stack deployment, template rendering
lua/backup/            Encrypted backup to S3-compatible storage (restic)
lua/maintain/          Rolling updates, health, scaling
lua/intake.lua         SSH/rsync gateway for static content
lua/roots/             Swarm, DNS, and network primitives
lua/soil/              Provider layer (Hetzner, DigitalOcean, BYOH)

garden/<name>/conf.lua             Stack definitions (self-describing)
.gardens/<g>/domains/<d>.lua       Domain configurations (per garden)

For the full technical story — why Lua, why Swarm, how the pieces fit, what we've learned — see BUILDING.md.

For the publishing system at the heart of it, see PRESS.md.

The name

Sweetgrass is a plant sacred to many Indigenous peoples of North America. It spreads through underground rhizomes, connecting in ways you can't see, binding the soil together. You can't eradicate it once it's established.

We chose the name because that's what we want this to be. Infrastructure that spreads through communities, that's impossible to shut down, that binds people together. Many small gardens, connected underground.

Contributing

This is community infrastructure. If you see something that could be better, make it better. The whole thing is readable. Start with BUILDING.md.

License

AGPL-3.0 — If you improve it, share it back.


Infrastructure doesn't have to be complicated. It doesn't have to be corporate. It can be ours.