Create a new Fx component following the modern (new-style) pattern with separate def/, fx/, and impl/ sub-packages.
IMPORTANT: NEVER use the legacy pattern (single-directory with fx.Provide directly). Always use the new-style pattern described below.
Instructions
Parse $ARGUMENTS to determine:
<bundle>/<component-name>: e.g., core/remoteflags means bundle=core, component=remoteflags
--team <team-name>: optional team ownership tag (default: ask the user)
--with-params: include a Params struct in the def package
--with-lifecycle: include compdef.Lifecycle in the Requires struct
--with-mock: also generate a mock/ sub-package
Ask the user (if not provided via arguments):
- What is the component's interface? (what methods should it expose?)
- Which team owns it? (for the
// team: comment)
- Does it need lifecycle hooks (start/stop)?
- Does it need a Params struct?
- What are its dependencies (other components it requires)?
Read reference examples before writing any code. Find a recent component under comp/ using the def/fx/impl pattern (e.g. comp/core/remoteagentregistry/). Read:
def/component.go — interface definition with // team: comment
fx/fx.go — Module() with fxutil.ProvideComponentConstructor
impl/<name>.go — Requires/Provides structs, NewComponent constructor
Create the directory structure under comp/<bundle>/<component>/:
comp/<bundle>/<component>/
├── def/
│ ├── go.mod
│ ├── component.go # Interface definition + team tag
│ └── params.go # (optional) Params struct
├── fx/
│ ├── go.mod
│ └── fx.go # Module() function
└── impl/
├── go.mod
└── <component>.go # Requires, Provides, NewComponent()
Create each file following the patterns from the reference. Key rules:
def/component.go: Package name = component name, include // team: comment, only interfaces
fx/fx.go: Use fxutil.ProvideComponentConstructor (NEVER raw fx.Provide), returns fxutil.Module
impl/<component>.go: Plain Go constructor func NewComponent(deps Requires) (Provides, error), no fx.In/fx.Out/compdef.In/compdef.Out embedding in Requires/Provides, unexported implementation type
go.mod files: Use v0.0.0 for inter-module dependencies, match Go version from root go.mod
Register the modules in modules.yml — add entries for def, fx, and impl (use default or used_by_otel: true).
Run dda inv create-module --path=comp/<bundle>/<component>/def (and for fx, impl) or manually add to modules.yml and run dda inv tidy.
Wire into a bundle if appropriate — add the component's Module() to the relevant comp/<bundle>/bundle.go.
Validate:
dda inv lint-components lint-fxutil-oneshot-test github.lint-codeowner
Fix any errors and re-run until clean.
Critical Rules (New-Style vs Legacy)
DO: def/fx/impl sub-packages, fxutil.ProvideComponentConstructor, plain Go constructor, plain Requires/Provides structs, thin def package.
DON'T: Single directory, fx.Provide(newComponent), fx.In/fx.Out embedding, implementation in def package.
Usage
/create-component core/myfeature --team agent-runtimes --with-lifecycle
/create-component metadata/hostinfo --team agent-metrics --with-params
1---2name: create-component3description: Create a new Fx component using the modern def/fx/impl pattern (NOT legacy)4---56Create a new Fx component following the **modern** (new-style) pattern with separate `def/`, `fx/`, and `impl/` sub-packages.78**IMPORTANT**: NEVER use the legacy pattern (single-directory with `fx.Provide` directly). Always use the new-style pattern described below.910## Instructions11121. **Parse `$ARGUMENTS`** to determine:13 - `<bundle>/<component-name>`: e.g., `core/remoteflags` means bundle=core, component=remoteflags14 - `--team <team-name>`: optional team ownership tag (default: ask the user)15 - `--with-params`: include a `Params` struct in the def package16 - `--with-lifecycle`: include `compdef.Lifecycle` in the Requires struct17 - `--with-mock`: also generate a `mock/` sub-package18192. **Ask the user** (if not provided via arguments):20 - What is the component's interface? (what methods should it expose?)21 - Which team owns it? (for the `// team:` comment)22 - Does it need lifecycle hooks (start/stop)?23 - Does it need a Params struct?24 - What are its dependencies (other components it requires)?25263. **Read reference examples** before writing any code. Find a recent component under `comp/` using the `def/fx/impl` pattern (e.g. `comp/core/remoteagentregistry/`). Read:27 - `def/component.go` — interface definition with `// team:` comment28 - `fx/fx.go` — Module() with `fxutil.ProvideComponentConstructor`29 - `impl/<name>.go` — Requires/Provides structs, NewComponent constructor30314. **Create the directory structure** under `comp/<bundle>/<component>/`:32 ```33 comp/<bundle>/<component>/34 ├── def/35 │ ├── go.mod36 │ ├── component.go # Interface definition + team tag37 │ └── params.go # (optional) Params struct38 ├── fx/39 │ ├── go.mod40 │ └── fx.go # Module() function41 └── impl/42 ├── go.mod43 └── <component>.go # Requires, Provides, NewComponent()44 ```45465. **Create each file** following the patterns from the reference. Key rules:47 - `def/component.go`: Package name = component name, include `// team:` comment, only interfaces48 - `fx/fx.go`: Use `fxutil.ProvideComponentConstructor` (NEVER raw `fx.Provide`), returns `fxutil.Module`49 - `impl/<component>.go`: Plain Go constructor `func NewComponent(deps Requires) (Provides, error)`, **no** `fx.In`/`fx.Out`/`compdef.In`/`compdef.Out` embedding in Requires/Provides, unexported implementation type50 - `go.mod` files: Use `v0.0.0` for inter-module dependencies, match Go version from root `go.mod`51526. **Register the modules** in `modules.yml` — add entries for `def`, `fx`, and `impl` (use `default` or `used_by_otel: true`).53547. **Run `dda inv create-module --path=comp/<bundle>/<component>/def`** (and for `fx`, `impl`) or manually add to `modules.yml` and run `dda inv tidy`.55568. **Wire into a bundle** if appropriate — add the component's `Module()` to the relevant `comp/<bundle>/bundle.go`.57589. **Validate**:59 ```bash60 dda inv lint-components lint-fxutil-oneshot-test github.lint-codeowner61 ```62 Fix any errors and re-run until clean.6364## Critical Rules (New-Style vs Legacy)6566**DO**: `def/fx/impl` sub-packages, `fxutil.ProvideComponentConstructor`, plain Go constructor, plain Requires/Provides structs, thin def package.6768**DON'T**: Single directory, `fx.Provide(newComponent)`, `fx.In`/`fx.Out` embedding, implementation in def package.6970## Usage7172- `/create-component core/myfeature --team agent-runtimes --with-lifecycle`73- `/create-component metadata/hostinfo --team agent-metrics --with-params`