AGENTS.md (6765B)
1 # AGENTS.md 2 3 ## Project overview 4 5 smithy-go is the Go code generator and runtime for [Smithy](https://smithy.io/). 6 It has two major components: 7 8 1. **Codegen** (`codegen/`) — A Smithy build plugin written in Java that 9 generates Go client/server/shape code from Smithy models. 10 2. **Runtime** (`./`, top-level Go module) — The Go packages that generated 11 code depends on at runtime. 12 13 The primary downstream consumer is 14 [aws-sdk-go-v2](https://github.com/aws/aws-sdk-go-v2). 15 16 ## Repository layout 17 18 ``` 19 . # Root Go module (github.com/aws/smithy-go) 20 ├── auth/ # Auth identity + scheme interfaces 21 │ └── bearer/ # Bearer token auth 22 ├── aws-http-auth/ # Separate module: AWS SigV4/SigV4A HTTP signing 23 ├── codegen/ # Java/Gradle: Smithy code generator 24 │ ├── smithy-go-codegen/ # Main codegen source (Java) 25 │ └── smithy-go-codegen-test/ # Codegen integration tests 26 ├── container/ # Generic container types 27 ├── context/ # Context helpers 28 ├── document/ # Smithy document type abstraction 29 │ └── json/ # JSON document codec 30 ├── encoding/ # Wire format encoders/decoders 31 │ ├── cbor/ # CBOR (used by rpcv2Cbor) 32 │ ├── httpbinding/ # HTTP binding serde helpers 33 │ ├── json/ # JSON encoder/decoder 34 │ └── xml/ # XML encoder/decoder 35 ├── endpoints/ # Endpoint resolution types 36 ├── internal/ # Internal utilities (singleflight, etc.) 37 ├── io/ # I/O helpers 38 ├── logging/ # Logging interfaces 39 ├── metrics/ # Metrics interfaces 40 │ └── smithyotelmetrics/ # Separate module: OpenTelemetry metrics adapter 41 ├── middleware/ # Middleware stack (the core of the operation pipeline) 42 ├── ptr/ # Pointer-to/from-value helpers 43 ├── testing/ # Test assertion helpers for generated protocol tests 44 │ └── xml/ # XML comparison utilities 45 ├── time/ # Smithy timestamp format helpers 46 ├── tracing/ # Tracing interfaces 47 │ └── smithyoteltracing/ # Separate module: OpenTelemetry tracing adapter 48 └── transport/ 49 └── http/ # HTTP request/response types and middleware 50 ``` 51 52 ## Building and testing 53 54 ### Runtime (Go) 55 56 ```bash 57 # Run unit tests 58 make unit 59 ``` 60 61 ### Codegen (Java) 62 63 ```bash 64 # Build and test codegen 65 cd codegen && ./gradlew build 66 67 # Publish to local Maven for downstream use 68 cd codegen && ./gradlew publishToMavenLocal 69 ``` 70 71 The codegen artifact version is published to Maven Central and bumped on each 72 release. For local development against unreleased codegen changes, use 73 `publishToMavenLocal` and point consumers at `mavenLocal()`. 74 75 ## Runtime architecture 76 77 ### Middleware stack 78 79 The operation pipeline is built on a middleware stack defined in `middleware/`. 80 Steps execute in order: Initialize → Serialize → Build → Finalize → 81 Deserialize. Each step is a `middleware.Step` that holds an ordered list of 82 middleware. The codegen generates middleware registrations for each operation. 83 84 ### Encoding packages 85 86 Each wire format has its own encoder/decoder under `encoding/`. These are 87 low-level — they produce/consume raw tokens or values, not full Smithy shapes. 88 Generated serde code calls into these packages. 89 90 ## Codegen: GoWriter and template system 91 92 GoWriter extends Smithy's `SymbolWriter` and is the primary mechanism for 93 generating Go source. It has **two distinct writing styles** that must not be 94 confused. 95 96 ### Style 1: Positional args (`writer.write` / `writer.openBlock`) 97 98 Inherited from `SymbolWriter`. Arguments are positional and referenced with 99 `$`-prefixed format characters. Each `$X` consumes the next argument in order. 100 101 Format characters: 102 - `$L` — Literal (toString). Strings, names, anything that should be inserted 103 verbatim. 104 - `$S` — String, quoted. Wraps the value in Go double-quotes. 105 - `$T` — Type (Symbol). Inserts the symbol name and auto-adds its import. 106 - `$P` — Pointable type (Symbol). Like `$T` but prepends `*` if the symbol is 107 marked pointable. 108 - `$W` — Writable. Evaluates a `Writable` (lambda/closure) inline. 109 - `$D` — Dependency. Adds a `GoDependency` import, expands to empty string. 110 111 Numbered variants (`$1L`, `$2T`, etc.) allow reusing the same argument 112 multiple times. The number is 1-indexed and refers to the position in the 113 argument list: 114 115 ```java 116 // $1L is used twice, $2L once — only 2 args needed 117 writer.write("type $1L struct{}\nvar _ $2L = (*$1L)(nil)", 118 DEFAULT_NAME, INTERFACE_NAME); 119 ``` 120 121 `openBlock`/`closeBlock` manage indentation for braced blocks. Arguments are 122 positional: 123 124 ```java 125 writer.openBlock("func (c $P) $T(ctx $T) ($P, error) {", "}", 126 serviceSymbol, operationSymbol, contextSymbol, outputSymbol, 127 () -> { 128 writer.write("return nil, nil"); 129 }); 130 ``` 131 132 ### Style 2: Named template args (`goTemplate` / `writeGoTemplate`) 133 134 Uses `$name:X` syntax where `name` is a key in a `Map<String, Object>` and `X` 135 is the format character. Arguments are passed as one or more maps. This is the 136 **preferred style for new code** — it is more readable and less error-prone 137 than positional args. 138 139 ```java 140 return goTemplate(""" 141 func $name:L(v $cborValue:T) ($type:T, error) { 142 return $coercer:T(v) 143 } 144 """, 145 Map.of( 146 "name", getDeserializerName(shape), 147 "cborValue", SmithyGoTypes.Encoding.Cbor.Value, 148 "type", symbolProvider.toSymbol(shape), 149 "coercer", coercer 150 )); 151 ``` 152 153 Rules: 154 - `goTemplate(String, Map...)` is a **static** method that returns a 155 `Writable` (a `Consumer<GoWriter>` lambda). It does NOT write immediately. 156 - `writeGoTemplate(String, Map...)` is an **instance** method that writes 157 immediately to the writer. 158 - Maps are merged into the writer's context scope for the duration of the 159 template. Multiple maps can be passed and are applied in order. 160 - The writer pre-populates common symbols in context: `fmt.Sprintf`, 161 `fmt.Errorf`, `errors.As`, `context.Context`, `time.Now`. 162 163 ### Composing writables 164 165 - `ChainWritable` — Collects multiple `Writable`s and composes them with 166 newlines between each. Use `.compose()` (with newlines) or 167 `.compose(false)` (without). 168 169 ### Symbol constants 170 171 For symbols, use `SmithyGoDependency.*.valueSymbol("Name")` or 172 `SmithyGoDependency.*.pointableSymbol("Name")`. 173