License: Apache 2.0
rho-kit is the standard Go service toolkit. It centralizes the
infrastructure patterns every service needs so teams can focus on domain logic
while staying consistent, secure, and observable.
- docs/RELEASE_NOTES_v2.md — historical v2.0.0 breaking-changes enumeration.
- CHANGELOG.md — per-release summary.
The kit is a Go multi-module workspace; releases use go.work as the
sole cross-module-resolution mechanism (no replace directives in
go.mod files). The one-time replace-drop was done at v2.0.0;
subsequent releases just bump version numbers and tag.
- Validate locally. Run
make release-candidate. It includes the policy and tidy checks, lint, race tests, builds, vulnerability analysis, integration tests, coverage, and kit-doctor. GitHub does not duplicate this exhaustive release-owner gate. - Rehearse locally (safe, no real origin touched).
Runs the entire dance against a temp bare repo. Must reach "Rehearsal passed." before touching origin. The manual
RELEASE_VERSION=v2.x.y bash tools/rehearse-v2-release.sh
Release RehearsalGitHub workflow exists only for validating release machinery changes; it is not required for every release. - Temporarily disable PR-review branch protection (the dance
pushes ~7 commits + tag batches directly to main; main is
normally PR-only):
gh api -X DELETE repos/<owner>/<repo>/branches/main/protection/required_pull_request_reviews
- Run the real release.
Per-level: bumps internal kit requires to the target version, tidies, commits, tags every module in the level, pushes tags atomically. Mechanical release commits contain
RELEASE_VERSION=v2.x.y bash tools/release-version.sh
[skip ci]so the dependency levels do not launch duplicate GitHub jobs. After all levels: pushes coordination tagrelease/v2.x.y. - Restore branch protection immediately. Capture the live protection
response before step 3 and restore those exact values. The current policy
is:
gh api -X PATCH repos/<owner>/<repo>/branches/main/protection/required_pull_request_reviews \ --input - <<EOF {"dismiss_stale_reviews": true, "require_code_owner_reviews": true, "require_last_push_approval": false, "required_approving_review_count": 0} EOF
- Smoke-test downstream resolution.
tmpdir=$(mktemp -d); cd "$tmpdir" go mod init verify go get github.com/bds421/rho-kit/app/[email protected] go list -m all | grep rho-kit # all should show v2.x.y
- Publish the GitHub Release. Use the version entry in
CHANGELOG.md, call out breaking changes, and link the comparison from the previous coordination tag. Do not reuse the historical v2.0.0 notes.
New downstream services should start with
docs/ai/adoption.md: minimum go.mod (the v2.x tags
are published, so require the versioned modules directly — no replace
block needed), the smallest compilable main.go, where each capability lives
in the decision tree, and the common first-mistake checklist. The package
decision tree in AGENTS.md is the
canonical "I need to X, what do I import?" reference.
Snippet status: Go blocks in this README are illustrative fragments. The shell
commands are executable from a downstream module. Golden-path evidence lives in
examples/agentic-service and the cmd/kit-new scaffold tests.
Why it exists
- Provide a single, opinionated "golden path" for service startup.
- Eliminate repeated boilerplate around logging, tracing, health, and config.
- Ship hardened primitives for data stores, messaging, and security.
Design principles
- Secure by default and fail fast on misconfiguration.
- Small, composable packages with explicit boundaries.
- Observability is never optional (logs, metrics, traces are first‑class).
- Safe defaults that scale in production without surprises.
app is the standard service entry point. It wires logging, health
endpoints, lifecycle management, and optional infrastructure like databases,
RabbitMQ, and JWT verification.
app.Main("backend", handler.Version, func(logger *slog.Logger) error {
base, err := app.LoadBaseConfig(8080)
if err != nil {
return err
}
return app.New("backend", handler.Version, base).
With(postgres.Module(pgxbackend.Config{DSN: os.Getenv("DATABASE_URL")})).
With(redis.Module(&goredis.Options{Addr: "cache.internal:6379", Password: "***", TLSConfig: &tls.Config{ServerName: "cache.internal"}})).
With(amqp.Module(os.Getenv("RABBITMQ_URL"))).
With(jwt.Module(os.Getenv("JWKS_URL"),
jwt.WithIssuer("https://issuer.example.com"),
jwt.WithAudience("backend"),
)).
With(ratelimit.IP(100, time.Minute)).
Router(func(infra app.Infrastructure) http.Handler {
return router.New(infra, logger)
}).
Run()
})Use app.LoadBaseConfig, sqldb.LoadFields, and package-specific loaders for
env-backed settings. Pass a hardened pgxbackend.Config to postgres.Module.
v2.0.0 lazy-adapter architecture. Heavy adapter wiring (Postgres, Redis,
RabbitMQ, NATS, OTel tracing, public gRPC) lives in per-adapter sub-modules
under app/: app/postgres, app/redis, app/amqp, app/nats,
app/tracing, app/grpc. Importing app/v2 alone no longer pulls pgx,
go-redis, amqp091, nats.go, otelgrpc, or grpc-go.
For credential rotation, prefer provider hooks over static secrets: pgx
PasswordProvider, go-redis credential providers, AMQP/NATS auth providers,
cloud SDK default credentials, CSRF WithSecrets, and signed-request
WrapKeyStore. See docs/ai/credential-rotation.md.
See examples/agentic-service for a full example.
csrfMW := csrf.New(
csrf.WithSecrets(cfg.CSRFSecret, cfg.PreviousCSRFSecrets...),
csrf.WithAllowedOrigins(cfg.PublicOrigin),
)
handler := stack.Default(router, logger,
stack.WithOuter(csrfMW, csrf.RequireJSONContentType),
)conn, err := kitredis.Connect(&goredis.Options{Addr: "localhost:6379"}, kitredis.WithInstance("cache"))
if err != nil {
log.Fatal(err)
}
c, err := rediscache.NewCache(conn.Client(), "api-cache")
if err != nil {
log.Fatal(err)
}
tenantCache := tenantcache.Wrap(c)
_ = tenantCache.Set(ctx, "profile:123", []byte("..."), time.Minute)# Each module ships independently and uses Go's /v2 path suffix.
go get github.com/bds421/rho-kit/app/v2
go get github.com/bds421/rho-kit/httpx/v2app– service bootstrap, infrastructure wiring, lifecycle, and graceful shutdown.core/config,core/apperror,core/validate,core/secret,core/tenant– configuration, typed errors, validation, and focused primitives.httpx,httpx/middleware/*,httpx/healthhttp,httpx/pagination,httpx/mcp– hardened HTTP servers, JSON helpers, middleware, health endpoints, pagination, and MCP handlers.cmd/kit-contract– portable OpenAPI/event-schema artifacts and conservative compatibility checks for CI.authz,authz/openfga,httpx/authz– authorization interfaces, OpenFGA adapter, and HTTP bridge.security/jwtutil,security/identity,security/netutil,security/csrf,security/asvs– JWT verification and canonical principals, mTLS/SSRF-safe networking, CSRF helpers, and ASVS scanning metadata.auth/oauth2,auth/oauth2/redis– provider-neutral browser OIDC and durable Redis session/state stores.app/oidc– Builder composition for OIDC login/callback/logout routes and session-to-principal projection.crypto/encrypt,crypto/envelope,crypto/paseto,crypto/passhash,crypto/signing– encryption, token, password, and request-signing primitives.infra/sqldb,infra/sqldb/pgx,infra/sqldb/dbtest– SQL contracts, pgx backend, migrations, and Docker-backed DB test helper module.infra/redis,infra/redis/redistest– resilient Redis connection management plus the split Docker-backed Redis test helper module.data/cache,data/cache/rediscache,data/idempotency,data/lock,data/queue,data/stream,data/ratelimit– data interfaces, memory implementations, and optional Redis/Postgres adapters.infra/messaging,infra/messaging/amqpbackend,infra/messaging/redisbackend,infra/messaging/natsbackend– message contracts, buffered delivery, RabbitMQ, Redis Streams, and NATS JetStream adapters.infra/inbox/postgres,infra/outbox,infra/outbox/postgres– durable inbound deduplication plus transactional outbound delivery for at-least-once messaging.infra/storagepluss3backend,azurebackend,gcsbackend,sftpbackend,storagehttp/uploadsec,storagehttp/uploadsec/clamav,storagetest– storage interfaces, cloud/SFTP/local backends, upload validation/scanning, and backend compliance tests.observability/health,observability/logging,observability/logattr,observability/redmetrics,observability/runtimemetrics,observability/slo,observability/pprof,observability/tracing– health, logs, metrics, profiling, SLOs, and tracing.runtime/lifecycle,runtime/concurrency,runtime/eventbus,runtime/cron,runtime/batchworker– lifecycle orchestration, worker patterns, eventing, and scheduling.resilience/retry,resilience/circuitbreaker,io/atomicfile,io/progress,flags– retries, circuit breakers, safe file writes, progress tracking, and feature flags.
auth.JWTpanics if the provider is nil to prevent accidental auth bypass.- Some packages intentionally panic on programmer errors to fail fast.
httpxintentionally avoids the stdlibnet/http/httputilname collision.- Resource names are used as Prometheus labels; keep them small and static.
ENVIRONMENT– set todevelopmentto enable dev-only behavior.LOG_LEVEL–debug,info,warn,error.SERVER_HOST,SERVER_PORT,INTERNAL_PORT– HTTP bind settings.TLS_CA_CERT,TLS_CERT,TLS_KEY– enable mTLS when all are set.DB_HOST,DB_PORT,<PREFIX>_DB_USER/_DB_PASSWORD/_DB_NAME– DB config.DB_SSL_MODE– PostgreSQL SSL mode (disable, allow, prefer, require, verify-ca, verify-full).RABBITMQ_URL– AMQP URL (Docker secrets supported via_FILE).