3.4 KiB
AGENTS.md — go-server-with-otel (template)
A ready-to-fork template app for the go-app framework: HTTP + gRPC +
grpc-gateway + MCP + OTEL/Prometheus, wired and building. Fork it, rename it,
replace the demo domain with your service. See go-app's AGENTS.md for
framework internals.
Kick off a new app (do these in order)
-
Rename via the Makefile (rewrites module path, binary/app name, Dockerfile, helm, buf
merge_file_name, main.goappName; deletes the old swagger file). GNUsedrequired (macOS:brew install gnu-sedor coreutils on PATH). The target is interactive, so pipe confirmation:echo y | make rename NAME=your.gitremote/pathto/newapp APP=new-app-nameIt does not rename the
demodomain — that's steps 4–6. Afterward verifygit grep go-server-with-otelis empty and update.gitea/workflows/ci.yml. -
Edit config (
pkg/config/custom.go): put app fields onServiceConfig(keep the embedded*config.AppConfig). Addenv:"..."tags for anything env-configurable — and see the env gotcha below. Updateconfig.yaml,env-sample, andhelm/values.yamlto match. Thenmake schema. -
Define your proto: replace
proto/demo/app/v1alpha1/withproto/<domain>/v1alpha1/, updatePROTO_DIRSin the Makefile, and runmake proto(buf; managed mode → generates intoapi/<same path>, so the protogo_packageoption is overridden — don't fight it). Deleteapi/demo. -
Implement
service.AppService(Init,GetGRPC,GetHTTP) in a newpkg/<domain>/package, mirroringpkg/demo:<domain>grpc/— gRPC impl (embedpb.Unimplemented...Server);GetServicesreturns*opts.GRPCService;GetDialOptsadds the insecure creds the gateway needs.<domain>mcp/—mcp.NewServerexposed asHTTPHandler{Prefix:"/api/mcp"}; tools viamcp.AddTool, typically delegating to the gRPC impl.- Remove
demohttp/unless you actually need plain HTTP funcs.
-
Register it in
main.go: setappServices = []service.AppService{&yoursvc}. This should be the only functional change inmain.go. -
Delete
pkg/demoand any remainingdemoreferences. -
Build/verify:
go build ./... && go test ./..., then run and hit/metrics,/api/...(REST),:8081(grpc + reflection),/api/mcp.
Gotchas the template inherits from go-app
- Custom-field env doesn't auto-apply.
MustLoadConfigIntoonly parses env for the embeddedAppConfig. Add aServiceConfig.LoadEnv()that runsenv.Parseover the custom fields (nil the embedded*AppConfigfirst to keep go-app's precedence) and call it inmain.goright afterMustLoadConfigInto. - REST gateway 404s unless
grpcGatewayPathStrip: trueis set in the grpc config (default is false, so the/apiprefix isn't stripped before matching). - Prometheus double-unit suffix: don't use
metric.WithUnitfor gauges whose names already carry the unit; the exporter appends another suffix. - MCP streamable HTTP: clients must POST to
/api/mcp/(trailing slash); the bare path 307-redirects.
What make rename does NOT touch
The demo domain naming: package dirs (pkg/demo*), proto/demo, api/demo,
types (DemoService, DemoAppService, DemoTool, …), PROTO_DIRS, and the
demo values in config.yaml/helm. Rename those by hand in steps 2–6.