Notes for AI Agents
Short, stable facts about GenDI for tooling and assistants. The same text is
served at https://gendi.dev/llms.txt, so an agent can read it in one fetch
instead of crawling this documentation.
The project is GenDI; the module, the command and the config file are all
lowercase gendi.
Schema
gendi.schema.json in the repository root is the machine-readable contract for
a config file — validate a generated config against it before running the
generator. A test keeps it in step with the loader, so what it rejects, the
loader rejects. Editors get the same checking from a first line of:
# yaml-language-server: $schema=https://raw.githubusercontent.com/gendi-org/gendi/master/gendi.schema.jsonAnything the schema accepts can still fail generation for reasons it cannot see — unknown service IDs, type mismatches against the real Go signatures, dependency cycles. Those are reported with the offending line and a caret.
CLI
go get -tool github.com/gendi-org/gendi/cmd/gendi # once, per module
go tool gendi --config=gendi.yaml --out=./di --pkg=diFlags: --config, --out, --pkg, --container, --build-tags, --enable-pass, --verbose.
YAML Syntax
Constructor args:
@service.idservice reference@.innerinner service (decorators only)%param.name%parameter!tagged:tag.nametagged injection!spread:@servicespread slice into variadic!spread:!tagged:tagspread tagged collection into variadic!go:pkg.SymbolGo package-level var/const (e.g.!go:os.Stdout)!field:@service.Fieldfield access on service (e.g.!field:@config.Host)!field:!go:pkg.Symbol.Fieldfield access on Go symbol (e.g.!field:!go:http.DefaultClient.Timeout)- literal scalars (string/int/float/bool/null)
Method constructors are configured via the constructor.method field
(method: "@factory.Create"), not as a constructor argument.
$this. in type and func fields, a tag’s element_type, !go: arguments,
and !field:!go: arguments resolves to the Go package path of the config file.
The method field takes no $this — it addresses a service, not a package.
Imports support exclude:
imports:
- path: ./services/*.yaml
exclude:
- ./services/test_*.yamlService Defaults
services._default sets the default shared, public, and autoconfigure
flags for the services of the same file (per file; not inherited across
imports). Any other field in _default is an error. Built-in defaults:
shared: true, public: false, autoconfigure: true.
Parameters
Declared as plain scalar defaults (no type field; null and mapping values
rejected):
parameters:
port: 8080
timeout: 5sThe target type is contextual — taken from each constructor argument. One
parameter may be injected as different types at different sites. Supported
targets: string, bool, all int/uint widths, float32, float64,
time.Duration, time.Time, and named types over those (static conversion
is generated). uintptr unsupported.
Runtime split: Provider.Lookup(name) (any, error) returns the raw value;
parameters.Caster (StandardCaster by default, override via
With<Container>ParameterCaster) converts it per injection site. Generated
code calls both through the parameters.Resolver facade struct:
c.paramsResolver.Int("port"). Unsupported
targets and non-convertible defaults fail at generation time; runtime
provider values are checked at construction with parameter name, service ID,
argument index, raw and target types in the error.
Spread Rules
- Only one
!spread:per constructor call - Must be the last argument
- Inner expression must resolve to a slice
- Target parameter must be variadic
Pruning
Public services (and public tags) are the generation roots. Services
unreachable from a root are dropped after validation, together with the
parameters only they injected. --enable-pass=expose-all makes everything
public and disables pruning.
Generated Container API
var DefaultContainerParameters *parameters.ProviderMap // injected YAML defaults; omitted when none survive pruning
func NewContainer(params parameters.Provider, opts ...ContainerOption) *Container
func (c *Container) GetServiceName() (ServiceType, error)
func (c *Container) MustServiceName() ServiceType
func WithContainerErrorHandler(handler func(serviceName string, err error)) ContainerOption
func WithContainerParameterCaster(caster parameters.Caster) ContainerOptionNewContainer(nil) uses DefaultContainerParameters, or
parameters.ProviderNullInstance when it is absent. Parameters no surviving
service injects are pruned from the defaults after unreachable services are
pruned; the variable is emitted only when at least one remains.
Available providers: NewProviderMap, NewProviderStructTag (di-param
struct tags), NewProviderComposite (last provider holding a name wins),
NewProviderNull.
Generated File Conventions
- Generated files are
*_gen.go - Banner:
// Code generated by gendi; DO NOT EDIT.