Landing page · Docs · Releases · CI
Your stack is ready. Come build. Every decision favors practical outcomes over abstract ideals. The stack optimizes for simplicity, consistency, and shipping software with minimal friction.
Every web project starts with the same conversation — pick a database, auth, router, reactive frontend, task queue… — and the project stalls at the decisions, installations, and configurations. Not at the code. This template answers those decisions once, ships them wired together, and documents how to change or remove each piece.
What it is not: a framework. Frameworks call your code and keep you on their release train; gogogo hands you wired, documented code and gets out of the way.
The manual lives on the site, not in this file: calionauta.github.io/gogogo/docs/
Page index (20 pages)
One-liners mirror the docs site manifest (site/build.mjs).
Get started
- overview — what gogogo is, who it is for, and the seven async layers it ships.
- motivation — the thesis: Go for almost everything, Zig as the named exception.
- getting-started — clone, run, first five minutes, and the commands you need.
Core
- architecture — directory layout, dependency direction, entry points, and route wiring gotchas.
- stack-layers — every dependency and why it is in the box.
- async-layers — the seven async layers, SSE Hub record-sync vs ephemeral signals, cross-instance and offline sync.
- features — every capability and its runtime opt-out.
- scope-taxonomy — Core / Plugin / Feature: the rule for deciding what is safe to delete.
- configuration — every environment variable and runtime constant.
- exception-to-go — Go-first policy: why Zig is an exceptional native boundary, plus the agent decision procedure.
Frontend
- todo-example — the Todo reference implementation and the contract to imitate.
- ui-skins — pluggable DaisyUI / Basecoat skins and the plugin contract.
- ui-sounds — vendored cuelume sound feedback and its accessibility contract.
Ship
- deploy — server layout, first-time setup, deploy workflow, build pipeline and version badge.
- desktop-mobile — Wails v3 desktop/mobile, edge sync, and the native window.
- admin-dashboard — admin surfaces, the single-cookie session, and the DagNats console.
- llm-and-credits — GoAI configuration and the optional ai-credits / BYOK plugin.
Operate
- local-ci — the five-tier feedback loop and make signoff.
- code-quality — the 33 linters, how to scope them, the Datastar-specific rules, and the
ruleguardrules that encode project footguns as CI failures. - troubleshooting — symptoms and where they actually come from.
- dagnats-bootstrap-workaround — the upstream DagNats bug behind the trigger console, and the removable seed that works around it.
Plus ARCHITECTURE.md — the canonical annotated dependency
graph, and AGENTS.md — the working rules for human and AI agents
in this repo. The rules an agent is meant to load live in
skills/gogogo-coding-standards
(Go + template standards, concurrency, perf, testing, the exception-to-go gate) — install
it with npx skills add calionauta/gogogo.
This repo is a GitHub template — click Use this template to get your own
copy, then rename it. Do not build inside a clone of the template itself: your
module path would stay github.com/calionauta/gogogo and
deploys would target the template's server directory.
# 1. Scaffold with the installer: one command installs (binaries +
# Go toolchain when missing), asks name/owner/plugins/features, renames,
# trims what you skip, writes AGENTS.md, then `make dev` takes this
# terminal — Ctrl-C stops dev. Needs curl + git, nothing else.
curl -sSfL https://raw.githubusercontent.com/calionauta/gogogo/master/install.sh | sh -s -- --run
# With Go already installed, the equivalent without curl|sh:
# go run github.com/calionauta/gogogo/cmd/gogogo@latest --run
# Manual fallback (no installer):
# gh repo create my-app --template calionauta/gogogo --clone
# cd my-app
# make rename NAME=my-app # add OWNER=myorg if not under calionauta
# make site # regenerate the published docs
# make dev # runThis command needs Go and git (checked up front) — or curl + git via the
binary install in CLI & MCP below, where
install.sh bootstraps Go when missing. Open http://localhost:8080
for the landing page, then http://localhost:8080/todo for the demo
(sign in with the seeded demo1@demo.app / demo1234456; demo2@demo.app takes the same password for two-user contention).
make renameonly rewrites this project's identity. Sibling repos under the same owner (ai-credits,datastar-lint,pi-leakguard) are real dependencies and are left alone.
One
make buildcompiles everything. No build tags, no feature matrix. Opt out at runtime with env vars (NATS_ENABLED=false,DAGNATS_ENABLED=false).
| Layer | Choice | Why |
|---|---|---|
| Language | Go 1.27 | Fast compilation, easy deploy, lean runtime. Go-first: Zig only as an exceptional native escape hatch (exception-to-go; the why: motivation) |
| Zero-config database and auth | Turso Database (SQLite-compatible, sqlc) + owned argon2id sessions | Zero-config Turso, cookie sessions, file-local storage — no separate service |
| Access control without a service | Casbin + users.role |
Roles on the user row, policy in one model, enforced before the handler; embedded policy by default, DB-backed when evolving (rbac) |
| Reactive UI with no JS framework | Templ + Datastar (SSE) + Tailwind v4 | Server-rendered HTML, ~12 KiB client, no JS framework build step |
| Two UI skins in one binary | DaisyUI v5 (default) + Basecoat | Both compiled into one binary, switchable at runtime |
| Background jobs with retry | goqite + SSE Hub | goqite executes with backoff; SSE Hub streams progress to the browser. No Redis |
| Workflows that survive a restart | DagNats | Multi-step workflows as declarative JSON; resume after a mid-run kill |
| Room ownership without races | GoAkt | One grain per room: heartbeat roster plus exactly-one presenter lock, supervised |
| Shared state that merges offline edits | Loro CRDT + Rough.js | Conflict-free state with no last-write-wins data loss |
| Realtime for one instance or many | SSE Hub + NATS JetStream | Per-user record push, plus cross-instance broadcast |
| AI features on any provider | GoAI + optional ai-credits | Any OpenAI-compatible provider; optional billing ledger + BYOK |
| Secrets encrypted at rest | age + ~/.secrets/ |
Local encryption. No vault, no cloud |
| Desktop apps on the same backend | Wails v3 + gogpu/ui | Native shells over the same backend, plus a no-HTTP frontend |
| Linting tuned for AI-written code | golangci-lint (33) + datastar-lint | Tuned for LLM-authored code: unchecked errors, context leaks, lost context propagation |
Full table with the reasoning behind each choice: stack-layers. Client weight per feature (measured): 0–48 KB of JS — the backend is the source of truth, the browser holds intent and cache.
Seven complementary layers, already inside, each with its own opt-out:
Background jobs that update the UI → goqite + SSE Hub (always on)
Workflows that survive a restart → DagNats as JSON (DAGNATS_ENABLED=false)
Collaboration without data loss → Loro CRDT (remove internal/collab/)
Live record updates, scoped per user → SSE Hub record-sync (always on)
Ephemeral UI signals → SSE Hub via Datastar (always on)
Broadcast across instances → JetStream (NATS_ENABLED=false)
Room ownership without races → GoAkt grains (GOAKT_ENABLED=false)
Records flow through the SSE Hub record event — scoped per user by the owner column, free of charge. The ephemeral channel is reserved for ephemeral signals (toasts, client counts, workflow progress). Mixing those two up is the most common mistake in Datastar apps; async-layers explains why the split matters.
Every capability is always compiled. Each has a documented opt-out.
| Capability | Opt-out |
|---|---|
| Todo app + live record-sync, stacked toasts, sound feedback | delete features/todo/ |
Queue + retry with exponential backoff, SSE lastRetry signal |
— (core) |
| AI Suggest via GoAI, or keyless simulated LLM for the demo | no GOAI_API_KEY and SIMULATE_LLM=false |
| Ask AI: model renders catalog UI (cards, tables, sections) via SSE | trim genui (bundle with Chat), or no GOAI_API_KEY and SIMULATE_LLM=false (demo answers keyless) |
| Chat: conversation over the same catalog, persisted per owner | trim genui (bundle with Ask AI), or no GOAI_API_KEY and SIMULATE_LLM=false |
| Review loop: writer → critic → classifier judge, streamed verdict | trim review, or no GOAI_API_KEY (real-LLM only; page shows a setup hint) |
| AI credits + BYOK relay + Stripe top-ups | CREDITS_ENABLED=false |
| Collaborative whiteboard (CRDT + presence + offline outbox) | trim whiteboard (bundle with notes + collab transport), or COLLAB_SNAPSHOTS=memory |
| Room presence demo (GoAkt grains: roster + presenter lock) | delete features/room/ |
| Shared notes (server-owned Loro Text, live peer text) | delete features/notes/ |
Durable WelcomeOnboarding workflow |
DAGNATS_ENABLED=false |
| Hybrid offline sync (Service Worker + Leaf Node) | OFFLINE_SYNC_ENABLED=false |
| Single-store persistence (Turso Database via sqlc) | — (core) |
| Multi-instance realtime | NATS_ENABLED=false |
| Public landing page + auth-gated config view | delete features/landing/, features/config/ |
| Wails v3 desktop/mobile + native window | delete cmd/desktop/, cmd/gui/ |
Infrastructure opts out with an env var. The installer automates the common
deletions — named presets included: go run ./cmd/gogogo --preset minimal
(core + todo + auth), no-ai, no-collab — see
cmd/gogogo/README.md. Product features also opt out
by deleting the package and its one wiring call — see
features.
Every non-test .go file under internal/ and features/ carries a SCOPE
annotation declaring its removal class. make check-scope enforces it in CI and
in your pre-commit hook.
| Annotation | Meaning | You would |
|---|---|---|
SCOPE:core 🔴 |
The binary does not work without it | Customize, never remove |
SCOPE:plugin 🟡 |
The binary works but loses a capability | Swap, or delete + remove the wiring call |
SCOPE:feature 🟢 |
A demo or add-on | Keep as reference, then remove |
The rule for agents: never delete a core file without asking; never
keep a feature file in production if the domain doesn't need it.
Full taxonomy and per-package removal table:
scope-taxonomy.
Three entry points, one engine (internal/installer — CLI and MCP execute
the same code path with the same receipts and proof):
llms.txt— the agent entry index: what to read per task, invariants to not relearn. Published map of the docs site:site/llms.txt(index) +site/llms-full.txt(complete texts).- Installer CLI —
go run ./cmd/gogogo advise --need "..."for opinions (reads nothing, changes nothing),--preset minimal|no-ai|no-collabor--plugins/--featureskeep lists +--dry-runto preview,gogogo add <unit>to reverse a trim. Full reference: cmd/gogogo/README.md. - MCP server —
cmd/gogogo-mcp(separate module, stdio):advise_stack,capabilities_list,trim_plan,trim_apply(requiresconfirm:true),check_tree,add_unit. Tool table in cmd/gogogo-mcp/README.md.
| What | URL |
|---|---|
| Todo & Whiteboard demo | gogogo.calionauta.com |
| Durable workflow console (DagNats) | gogogo.calionauta.com/dagnats/ |
Sign in as demo1@demo.app / demo1234456 (demo2@demo.app takes the same
password — open a second browser or incognito window to be both at once and
prove contention, shared-vs-private todos, and authorship).
make dev # Live reload with Air (regenerates templ + CSS)
make build # Build binary (unified: everything included)
make ci-local # Full local gate (= CI): templ, lint, checks, build, boot smoke, parallel fan-out (race + browser smokes)
make signoff # ci-local + gh signoff stamp — the recommended pre-push gate
make setup # Activate lefthook git hooks + verify agent tooling
make site # Rebuild the docs site from docs/*.mdFull command reference: getting-started.
Humans get the guided installer above. Agents get the same engine
(internal/installer) through two scripted paths — opinions first,
preview second, mutation last. Full guides live in their own section:
docs/cli.md and docs/mcp.md.
| Path | Use when | Entry point |
|---|---|---|
advise |
deciding what to keep (use-case → keep/drop + off-switches + Go/Zig rule). Changes nothing | go run ./cmd/gogogo advise --need "..." --format json |
trim --dry-run |
previewing the scaffold as one JSON document | --no-tui --dry-run --format json (add --yes to apply) |
add / --check |
restoring a unit into a scaffolded checkout / verifying markers | add <unit> --from <pristine> --dir <proj> [--dry-run|--yes] |
| MCP server | tool calls instead of shell (advise_stack, capabilities_list, trim_plan, trim_apply, check_tree, add_unit) |
cmd/gogogo-mcp (own module, stdio) + one JSON block in the client config |
Destructive paths refuse without explicit confirmation (--yes /
confirm:true). Strategy and the foreign-codebase boundary:
getting-started §0b–0c.
No Go on this machine? Tagged releases ship static binaries (gogogo +
gogogo-mcp, checksummed) — and install.sh bootstraps a user-space Go
toolchain when none is found (~/.local/go, no sudo, existing installs
untouched). It does not symlink go into ~/.local/bin: that directory is on
your PATH, so the link would win over a system Go. It exports
~/.local/go/bin for the install and prints the line to persist it. Same one-liner as the quick start above (it is the quick
start — append anything after --run and it reaches gogogo):
make ci-local locally is the same gate CI runs, and make signoff adds a git
stamp. It catches ~95% of regressions in under 3 minutes instead of waiting on a
CI round trip. The tier ladder (T1 format/build → T5 signoff) and what each tier
catches: local-ci.
The most valuable contribution right now is using gogogo for a real project and reporting what broke — see CONTRIBUTING.md.
AI-assisted contributions are welcome, with a human in the loop: disclose
tool use in the PR body (no AI trailers in commits or changelogs), explain
motivation, include a reproduction, keep the diff minimal, and run
make signoff before pushing. Please discuss features in an issue before
opening a PR.
Inspired by northstar by Zangster — a Go + NATS + Datastar + Templ + DaisyUI application starter. See docs/inspirations.md for full credits and learnings.
MIT — see LICENSE. Open to feedback, PRs, and adaptations. If something doesn't make sense, if the stack doesn't fit your problem, or if you have a better idea, open an issue.
