6.5 KiB
AGENTS.md
Project overview
smithy-go is the Go code generator and runtime for Smithy. It has two major components:
- Codegen (
codegen/) — A Smithy build plugin written in Java that generates Go client/server/shape code from Smithy models. - Runtime (
./, top-level Go module) — The Go packages that generated code depends on at runtime.
The primary downstream consumer is aws-sdk-go-v2.
Repository layout
. # Root Go module (github.com/aws/smithy-go)
├── auth/ # Auth identity + scheme interfaces
│ └── bearer/ # Bearer token auth
├── aws-http-auth/ # Separate module: AWS SigV4/SigV4A HTTP signing
├── codegen/ # Java/Gradle: Smithy code generator
│ ├── smithy-go-codegen/ # Main codegen source (Java)
│ └── smithy-go-codegen-test/ # Codegen integration tests
├── container/ # Generic container types
├── context/ # Context helpers
├── document/ # Smithy document type abstraction
│ └── json/ # JSON document codec
├── encoding/ # Wire format encoders/decoders
│ ├── cbor/ # CBOR (used by rpcv2Cbor)
│ ├── httpbinding/ # HTTP binding serde helpers
│ ├── json/ # JSON encoder/decoder
│ └── xml/ # XML encoder/decoder
├── endpoints/ # Endpoint resolution types
├── internal/ # Internal utilities (singleflight, etc.)
├── io/ # I/O helpers
├── logging/ # Logging interfaces
├── metrics/ # Metrics interfaces
│ └── smithyotelmetrics/ # Separate module: OpenTelemetry metrics adapter
├── middleware/ # Middleware stack (the core of the operation pipeline)
├── ptr/ # Pointer-to/from-value helpers
├── testing/ # Test assertion helpers for generated protocol tests
│ └── xml/ # XML comparison utilities
├── time/ # Smithy timestamp format helpers
├── tracing/ # Tracing interfaces
│ └── smithyoteltracing/ # Separate module: OpenTelemetry tracing adapter
└── transport/
└── http/ # HTTP request/response types and middleware
Building and testing
Runtime (Go)
# Run unit tests
make unit
Codegen (Java)
# Build and test codegen
cd codegen && ./gradlew build
# Publish to local Maven for downstream use
cd codegen && ./gradlew publishToMavenLocal
The codegen artifact version is fixed at 0.1.0 and is not published to
Maven Central — you MUST publishToMavenLocal.
Runtime architecture
Middleware stack
The operation pipeline is built on a middleware stack defined in middleware/.
Steps execute in order: Initialize → Serialize → Build → Finalize →
Deserialize. Each step is a middleware.Step that holds an ordered list of
middleware. The codegen generates middleware registrations for each operation.
Encoding packages
Each wire format has its own encoder/decoder under encoding/. These are
low-level — they produce/consume raw tokens or values, not full Smithy shapes.
Generated serde code calls into these packages.
Codegen: GoWriter and template system
GoWriter extends Smithy's SymbolWriter and is the primary mechanism for
generating Go source. It has two distinct writing styles that must not be
confused.
Style 1: Positional args (writer.write / writer.openBlock)
Inherited from SymbolWriter. Arguments are positional and referenced with
$-prefixed format characters. Each $X consumes the next argument in order.
Format characters:
$L— Literal (toString). Strings, names, anything that should be inserted verbatim.$S— String, quoted. Wraps the value in Go double-quotes.$T— Type (Symbol). Inserts the symbol name and auto-adds its import.$P— Pointable type (Symbol). Like$Tbut prepends*if the symbol is marked pointable.$W— Writable. Evaluates aWritable(lambda/closure) inline.$D— Dependency. Adds aGoDependencyimport, expands to empty string.
Numbered variants ($1L, $2T, etc.) allow reusing the same argument
multiple times. The number is 1-indexed and refers to the position in the
argument list:
// $1L is used twice, $2L once — only 2 args needed
writer.write("type $1L struct{}\nvar _ $2L = (*$1L)(nil)",
DEFAULT_NAME, INTERFACE_NAME);
openBlock/closeBlock manage indentation for braced blocks. Arguments are
positional:
writer.openBlock("func (c $P) $T(ctx $T) ($P, error) {", "}",
serviceSymbol, operationSymbol, contextSymbol, outputSymbol,
() -> {
writer.write("return nil, nil");
});
Style 2: Named template args (goTemplate / writeGoTemplate)
Uses $name:X syntax where name is a key in a Map<String, Object> and X
is the format character. Arguments are passed as one or more maps. This is the
preferred style for new code — it is more readable and less error-prone
than positional args.
return goTemplate("""
func $name:L(v $cborValue:T) ($type:T, error) {
return $coercer:T(v)
}
""",
Map.of(
"name", getDeserializerName(shape),
"cborValue", SmithyGoTypes.Encoding.Cbor.Value,
"type", symbolProvider.toSymbol(shape),
"coercer", coercer
));
Rules:
goTemplate(String, Map...)is a static method that returns aWritable(aConsumer<GoWriter>lambda). It does NOT write immediately.writeGoTemplate(String, Map...)is an instance method that writes immediately to the writer.- Maps are merged into the writer's context scope for the duration of the template. Multiple maps can be passed and are applied in order.
- The writer pre-populates common symbols in context:
fmt.Sprintf,fmt.Errorf,errors.As,context.Context,time.Now.
Composing writables
ChainWritable— Collects multipleWritables and composes them with newlines between each. Use.compose()(with newlines) or.compose(false)(without).
Symbol constants
For symbols, use SmithyGoDependency.*.valueSymbol("Name") or
SmithyGoDependency.*.pointableSymbol("Name").