chore: updated skills 54f3285f
Steve Simkins · 2026-05-20 21:34 1 file(s) · +41 −41
skills/andromeda-stack/SKILL.md +41 −41
1 1
---
2 2
name: Andromeda Stack
3 -
description: Scaffold a Go CRUD web app using net/http + html/template + modernc.org/sqlite + the shared andromeda crates-go packages (auth, web, config, sqlite, darkmatter). Use when the user wants to build a new Go web server with CRUD operations in the andromeda monorepo.
3 +
description: Scaffold a Go CRUD web app using net/http + html/template + modernc.org/sqlite + the shared andromeda pkg packages (auth, web, config, sqlite, darkmatter). Use when the user wants to build a new Go web server with CRUD operations in the andromeda monorepo.
4 4
---
5 5
6 6
# Go Andromeda Web App
9 9
10 10
Scaffold and build Go CRUD web apps in the andromeda workspace using the
11 11
standard library `net/http` mux, `html/template`, `modernc.org/sqlite` (pure
12 -
Go, no cgo) and the shared `crates-go/*` packages. Each app ships a single Go
12 +
Go, no cgo) and the shared `pkg/*` packages. Each app ships a single Go
13 13
binary with HTML pages, a JSON API, optional session or API key auth, embedded
14 14
templates + static assets via `embed.FS`, and Docker deployment.
15 15
16 16
Apps live under `apps/<name>/`. Each app is its own Go module. Shared packages
17 -
live under `crates-go/` and are each their own module, wired in via local
17 +
live under `pkg/` and are each their own module, wired in via local
18 18
`replace` directives.
19 19
20 20
Shared crates:
21 21
22 -
- `crates-go/auth` — session `Store`, `RequireSession` / `RequireAPIKey` /
22 +
- `pkg/auth` — session `Store`, `RequireSession` / `RequireAPIKey` /
23 23
  `RequireBearerOrSession` middleware, `SecureEqual`, `VerifyPassword`
24 24
  (bcrypt or plaintext), `GenerateSessionToken`, `GenerateShortID`.
25 -
- `crates-go/web` — `Render`, `WriteJSON`, `WriteError`, `DecodeJSON`,
25 +
- `pkg/web` — `Render`, `WriteJSON`, `WriteError`, `DecodeJSON`,
26 26
  `EmbeddedHandler`, `RedirectWithError`, `RedirectWithSuccess`, `PathInt64`.
27 -
- `crates-go/config` — `LoadDotEnv`, `Getenv`, `GetenvInt`, `GetenvBool`.
28 -
- `crates-go/sqlite` — `Open(path, schema)` opens SQLite with the project
27 +
- `pkg/config` — `LoadDotEnv`, `Getenv`, `GetenvInt`, `GetenvBool`.
28 +
- `pkg/sqlite` — `Open(path, schema)` opens SQLite with the project
29 29
  defaults (`PRAGMA foreign_keys=ON`, `SetMaxOpenConns(1)`).
30 -
- `crates-go/darkmatter` — embedded shared CSS + fonts plus `Mount(mux,
30 +
- `pkg/darkmatter` — embedded shared CSS + fonts plus `Mount(mux,
31 31
  "/assets")` to register routes on any `*http.ServeMux`.
32 32
33 33
## Project Structure
67 67
go 1.25
68 68
69 69
require (
70 -
	github.com/stevedylandev/andromeda/crates-go/auth v0.0.0
71 -
	github.com/stevedylandev/andromeda/crates-go/config v0.0.0
72 -
	github.com/stevedylandev/andromeda/crates-go/darkmatter v0.0.0
73 -
	github.com/stevedylandev/andromeda/crates-go/sqlite v0.0.0
74 -
	github.com/stevedylandev/andromeda/crates-go/web v0.0.0
70 +
	github.com/stevedylandev/andromeda/pkg/auth v0.0.0
71 +
	github.com/stevedylandev/andromeda/pkg/config v0.0.0
72 +
	github.com/stevedylandev/andromeda/pkg/darkmatter v0.0.0
73 +
	github.com/stevedylandev/andromeda/pkg/sqlite v0.0.0
74 +
	github.com/stevedylandev/andromeda/pkg/web v0.0.0
75 75
)
76 76
77 77
replace (
78 -
	github.com/stevedylandev/andromeda/crates-go/auth       => ../../crates-go/auth
79 -
	github.com/stevedylandev/andromeda/crates-go/config     => ../../crates-go/config
80 -
	github.com/stevedylandev/andromeda/crates-go/darkmatter => ../../crates-go/darkmatter
81 -
	github.com/stevedylandev/andromeda/crates-go/sqlite     => ../../crates-go/sqlite
82 -
	github.com/stevedylandev/andromeda/crates-go/web        => ../../crates-go/web
78 +
	github.com/stevedylandev/andromeda/pkg/auth       => ../../pkg/auth
79 +
	github.com/stevedylandev/andromeda/pkg/config     => ../../pkg/config
80 +
	github.com/stevedylandev/andromeda/pkg/darkmatter => ../../pkg/darkmatter
81 +
	github.com/stevedylandev/andromeda/pkg/sqlite     => ../../pkg/sqlite
82 +
	github.com/stevedylandev/andromeda/pkg/web        => ../../pkg/web
83 83
)
84 84
```
85 85
86 -
Add `crates-go/tui` only if the app ships a TUI. Add `golang.org/x/crypto`,
86 +
Add `pkg/tui` only if the app ships a TUI. Add `golang.org/x/crypto`,
87 87
`yuin/goldmark`, etc. only when the specific app needs them. The Dockerfile
88 -
must copy `crates-go/` into the build context for the replace directives.
88 +
must copy `pkg/` into the build context for the replace directives.
89 89
90 90
Do NOT add ORMs, web frameworks (gin, echo, chi), connection pools, or HTTP
91 91
client libs unless explicitly requested. The stdlib `net/http` mux (with
105 105
	"net/http"
106 106
	"os"
107 107
108 -
	"github.com/stevedylandev/andromeda/crates-go/auth"
109 -
	"github.com/stevedylandev/andromeda/crates-go/config"
108 +
	"github.com/stevedylandev/andromeda/pkg/auth"
109 +
	"github.com/stevedylandev/andromeda/pkg/config"
110 110
)
111 111
112 112
func main() {
176 176
	"html/template"
177 177
	"log/slog"
178 178
179 -
	"github.com/stevedylandev/andromeda/crates-go/auth"
179 +
	"github.com/stevedylandev/andromeda/pkg/auth"
180 180
)
181 181
182 182
//go:embed templates/*.html static/*
215 215
import (
216 216
	"net/http"
217 217
218 -
	"github.com/stevedylandev/andromeda/crates-go/auth"
219 -
	"github.com/stevedylandev/andromeda/crates-go/darkmatter"
220 -
	"github.com/stevedylandev/andromeda/crates-go/web"
218 +
	"github.com/stevedylandev/andromeda/pkg/auth"
219 +
	"github.com/stevedylandev/andromeda/pkg/darkmatter"
220 +
	"github.com/stevedylandev/andromeda/pkg/web"
221 221
)
222 222
223 223
func (a *App) routes() *http.ServeMux {
263 263
264 264
## db.go (or internal/store)
265 265
266 -
Single-file module: schema, model, CRUD. `crates-go/sqlite.Open` handles the
266 +
Single-file module: schema, model, CRUD. `pkg/sqlite.Open` handles the
267 267
driver, pragmas, and schema bootstrap.
268 268
269 269
```go
273 273
	"database/sql"
274 274
	"errors"
275 275
276 -
	"github.com/stevedylandev/andromeda/crates-go/auth"
277 -
	"github.com/stevedylandev/andromeda/crates-go/sqlite"
276 +
	"github.com/stevedylandev/andromeda/pkg/auth"
277 +
	"github.com/stevedylandev/andromeda/pkg/sqlite"
278 278
)
279 279
280 280
type Item struct {
396 396
	"net/http"
397 397
	"strings"
398 398
399 -
	"github.com/stevedylandev/andromeda/crates-go/auth"
400 -
	"github.com/stevedylandev/andromeda/crates-go/web"
399 +
	"github.com/stevedylandev/andromeda/pkg/auth"
400 +
	"github.com/stevedylandev/andromeda/pkg/web"
401 401
)
402 402
403 403
func (a *App) loginGetHandler(w http.ResponseWriter, r *http.Request) {
467 467
import (
468 468
	"net/http"
469 469
470 -
	"github.com/stevedylandev/andromeda/crates-go/web"
470 +
	"github.com/stevedylandev/andromeda/pkg/web"
471 471
)
472 472
473 473
func (a *App) apiListItems(w http.ResponseWriter, r *http.Request) {
514 514
515 515
## Authentication
516 516
517 -
`crates-go/auth` provides three middleware patterns. Pick based on app shape:
517 +
`pkg/auth` provides three middleware patterns. Pick based on app shape:
518 518
519 519
### Session/cookie auth (web-facing apps)
520 520
631 631
632 632
## Dockerfile
633 633
634 -
Multi-stage, built from the repo root so `crates-go/` is available for the
634 +
Multi-stage, built from the repo root so `pkg/` is available for the
635 635
`replace` directives. Pure Go (`CGO_ENABLED=0`) because the SQLite driver is
636 636
`modernc.org/sqlite`.
637 637
639 639
# Build from repo root: docker build -t APP_NAME -f apps/APP_NAME/Dockerfile .
640 640
FROM golang:1.25-bookworm AS builder
641 641
WORKDIR /app
642 -
COPY crates-go/ ./crates-go/
642 +
COPY pkg/ ./pkg/
643 643
COPY apps/APP_NAME/go.mod apps/APP_NAME/go.sum ./apps/APP_NAME/
644 644
WORKDIR /app/apps/APP_NAME
645 645
RUN go mod download
763 763
make go-app-fmt  APP=APP_NAME
764 764
```
765 765
766 -
The shared crates (`crates-go/web`, `crates-go/auth`, `crates-go/config`,
767 -
`crates-go/sqlite`, `crates-go/darkmatter`) are each their own module — run
766 +
The shared crates (`pkg/web`, `pkg/auth`, `pkg/config`,
767 +
`pkg/sqlite`, `pkg/darkmatter`) are each their own module — run
768 768
`go build ./...` inside any to check in isolation.
769 769
770 770
## Checklist
776 776
3. `main.go` — env load, DB open, sessions bootstrap, `App` build, `ListenAndServe`.
777 777
4. `app.go` — `App` struct, `//go:embed`, page-data structs.
778 778
5. `routes.go` — mux wiring, middleware, `/static/` + `darkmatter.Mount`.
779 -
6. `db.go` — schema, model, CRUD via `crates-go/sqlite.Open`.
779 +
6. `db.go` — schema, model, CRUD via `pkg/sqlite.Open`.
780 780
7. `handlers_web.go` — login/logout + HTML CRUD pages.
781 781
8. `handlers_api.go` — JSON CRUD endpoints behind `RequireAPIKey`.
782 782
9. `templates/base.html` + per-page templates using `{{ define }}` blocks.
794 794
- No web frameworks (gin, echo, chi, fiber) — stdlib `net/http` mux is enough.
795 795
- No ORMs — raw `database/sql` + `?` placeholders.
796 796
- No connection pools — `sqlite.Open` sets `MaxOpenConns(1)` on purpose.
797 -
- No cgo SQLite drivers — use `modernc.org/sqlite` via `crates-go/sqlite`.
798 -
- No external CSS frameworks unless specified — use `crates-go/darkmatter`.
797 +
- No cgo SQLite drivers — use `modernc.org/sqlite` via `pkg/sqlite`.
798 +
- No external CSS frameworks unless specified — use `pkg/darkmatter`.
799 799
- No JS frontend / build step — `html/template` rendered server-side.
800 800
- No CLI / TUI deps (cobra, bubbletea) unless the app actually needs them.
801 -
- No `replace` directives for anything outside `crates-go/`.
801 +
- No `replace` directives for anything outside `pkg/`.