Use bin/AGENTS.md for shared skills and cross-repository defaults.
- Library repo; check
go.modfor module and toolchain details. - DI is under
di/; CLI helpers are undercli/. - Many
maketargets come from thebin/submodule.
- Initialize the submodule before using shared Make targets. Use
make submoduleonce the sharedbincheckout is present; seebin/AGENTS.mdfor fresh-clone bootstrap details. - Submodule fetches use SSH.
- Discover targets:
make help. - Dependencies:
make depafter dependency changes. - Quality:
make specs,make lint,make fix-lint,make format,make sec. - Coverage and benchmarks: use the repo
maketargets shown bymake help. - TLS fixtures:
make create-certswhen the target is relevant.
- Feature packages usually use
config.go,module.go, plus implementation files. module/exports the main Fx bundles.config/owns top-level config plus projections into transport, SQL, and telemetry config.net/holds lower-level HTTP/gRPC, metadata, header, and server helpers.transport/holds the higher-level HTTP/gRPC stacks, middleware, and ops endpoints.internal/test/contains shared test helpers;test/stores fixtures and reports.internal/testprotobufs are test fixtures, not an external API contract. Usemake -C internal/test generate/stalewhen changing them, but do not treat the inheritedbreakingtarget as applicable there; the shared Buf target assumes anapi/contract directory.- Modules are composed with
di.Module(...); many constructors usedi.In.
config.NewDecoderresolves-config/-casfile:<path>,env:<ENV_VAR>, or a default config file named for the service.- Default file lookup checks the executable directory,
$XDG_CONFIG_HOME/<serviceName>/, and/etc/<serviceName>/. Default lookup may resolve the user config directory before probing file candidates, so HOME or XDG_CONFIG_HOME is expected to be available when default lookup starts; missing both is treated as a misconfigured runtime. Do not flag the resultingos.UserConfigDirpanic as a config issue. Services that do not want this environment contract should pass an explicit-config file:<path>or-config env:<ENV_VAR>source. - Many config fields use source strings through
os.FS.ReadSource:env:NAME,file:/path, or a literal value. - Source strings are administrator-supplied configuration. This repository
accepts that admins must point file/env/literal sources at appropriate
material, including reasonably sized secrets, keys, certificates, access
models, policies, DSNs, and service config files. Do not flag unbounded
ReadSource/ReadFilebehavior solely because a misconfigured admin could point a source string at an unexpectedly large file, env var, or literal. Report only concrete bugs where untrusted runtime input controls the source, documented size limits are ignored, or a public API promises bounded source reads. - Low-level
config/options.Mapvalues are administrator-supplied tuning knobs. Do not flag size-valued options such as HTTPmax_header_bytesor gRPCmax_header_list_size,initial_window_size,initial_conn_window_size, ormax_send_msg_sizesolely because an admin can configure values abovebytes.MaxConfigSize.bytes.MaxConfigSizeapplies only where a typed config field or public API explicitly promises that repository-owned cap, such asMaxReceiveSizevalidation. Report only concrete bugs such as ignored typed validation, untrusted runtime input controlling the option, destination-type overflow, or documented bounds being bypassed. - Service configuration files should contain configuration values and secret source references, not raw passwords or credentials.
- Nil pointer sub-configs usually mean "disabled".
- Downstream services that need application-specific configuration compose the
standard
module.Serverormodule.Clientbundle with a service-localinternal/config.Module. The supported pattern is to provideconfig.NewConfig[ServiceConfig], decorate the embedded shared*config.Config, and expose service-specific projections with constructors. Do not flag the absence of generic helpers such asmodule.ServerWithConfig[T]ormodule.ClientWithConfig[T]as a feature gap solely because services need custom typed config. Report only concrete bugs where the documented/template pattern fails, duplicate config decoding is forced by supported wiring, projections cannot be supplied throughdi.Decorate, or the support boundary changes. - Standard module wiring is the supported path. Do not flag hypothetical failures that require hand-wiring an incomplete DI graph unless the public API explicitly promises that custom construction mode.
- An exported constructor, setter, helper, option, or other symbol does not make every direct invocation or argument a supported contract. Before recording an issue that cannot occur through standard module, CLI, template, or integration wiring, identify a current supported consumer or an explicit contract for the exact construction and triggering input. Package-local tests of nil, zero, invalid, or defensive branches do not establish supported usage by themselves. If no supported path supplies the triggering input, reject the candidate as unsupported misuse.
- Recommend Fx
optional:"true"dependency tags only with concrete evidence that a supported DI graph may omit that dependency. A nil check, "optional" prose, or guarded hook installation is a lead, not enough by itself; verify standardmodule.Server/module.Clientwiring, CLI/server application wiring, a config-disabled path, or existing supported test/user wiring where the dependency can genuinely be absent. Directly composing an exported lower-level module is not enough evidence unless a public contract explicitly promises that module works standalone without the standard bundle. If the standard module bundle always resolves the dependency and no such lower-level contract exists, do not flag the missing optional tag. *os.FSdependencies are provided by the supported DI wiring path and are expected to be non-nil there. Do not flag nil-*os.FSpanics in token, crypto, config, or source-string loading paths based solely on manually calling constructors with nil filesystem dependencies unless a public API explicitly promises nil-FS tolerance or a supported path can provide nil.
- Treat compatibility-affecting changes that have landed in repository history as accepted decisions, even when they appear semver-incompatible or require downstream source changes. Do not flag or reopen them solely by comparing current code with older tags, releases, documentation, examples, or exported surfaces. Review current code against the current supported behavior, and revisit a landed compatibility decision only when the user explicitly asks.
Before recording a finding, review candidate, audit entry, or proposed change,
agents MUST read the index docs/agents/accepted-design.md and every area file
under docs/agents/accepted-design/ that is relevant to their scope. When a
scope spans several areas or relevance is unclear, read every candidate area
file. These files record the accepted designs, intentional tradeoffs, and
support boundaries that agents repeatedly re-flag as bugs, covering transport,
TLS, config, telemetry, limiters, tokens, crypto, debug endpoints, encoding,
MVC, health, and CLI lifecycle surfaces. Those rules are mandatory and carry the
same weight as this file. Agents MUST NOT report a finding in those areas
without checking the relevant area files first.
- Tests commonly use
stretchr/testify/require. - When adding test coverage, first follow the existing test shape in the package. Prefer extending current fixture/table/assertion helpers over adding standalone tests for behavior already exercised nearby.
- Config tests usually use fixture-driven
config.NewConfigcoverage plusverifyConfig; do not add separate decoder-routing or Fx projection tests unless they cover a distinct repository-owned behavior not already exercised by those fixture tests. - Do not add build-tagged or architecture-specific tests unless CI actually runs that build tag or architecture.
- Go files use tabs; YAML uses 2 spaces per
.editorconfig. - Every exported identifier, including under
internal/test/**, needs a GoDoc comment. - GoDoc comments should start with the identifier name or
Deprecated:.
- CI initializes submodules, prepares certs/services, then runs dependency, lint, security, spec, benchmark, and coverage targets.
- Check CI config for exact service dependencies, ports, and command order.
- CircleCI owns the selected dependency sidecars. Do not flag the sidecar selection as a reliability, release-safety, or reproducibility gap solely because it is CI-owned; report only concrete breakage such as CI no longer starting the required service, waiting on the wrong port, or using a dependency that no longer satisfies the documented test dependency.
- The
timepackage intentionally exercises multiple live public NTP/NTS providers in normal tests as smoke coverage for the network time adapters. Do not flag those tests or themake specsCI path solely because they perform internet/network time queries. Report only concrete breakage such as all configured providers currently failing in CI, ignored timeouts, removed provider redundancy, or a documented promise of hermetic/offline specs. - Agents verifying changes in a sandboxed shell should run
make specs(optionallypackage=<path>to scope it) rather than a rawgo testinvocation, especially for anything touching or depending on thetimepackage. In at least one sandboxed agent environment, rawgo testagainsttime's NTP/NTS tests failed reproducibly (dial udp/tcp ...: operation not permitted) whilepackage=time make specspassed reproducibly for the same code, same machine, same session —make specswraps the samego testinvocation (seebin/build/go/test), so the difference is in how that sandbox's tooling permission/network layer treats the two invocations, not in what the repo's tests do. Do not conclude live NTP/NTS coverage is broken from a rawgo testfailure alone; reproduce throughmake specsbefore treating it as a real breakage.