Add a New Backend
Use this guide when introducing a new provider/backend in honey.
1) Add config model
In internal/config/config.go:
- define
type NewBackend struct { ... } - add a field to the
Backendsstruct:NewBackend []NewBackendwith matchingyaml/jsontags, e.g.`yaml:"newbackend" json:"newbackend" honey:"label=My Backend;order=70" validate:"dive" mod:"dive"`
Use snake_case tags for YAML compatibility and add honey tags for schema metadata.
Typical tag usage on each backend field:
honey:"label=Token;secret"honey:"label=Mode;enum=nodes|pods;enum_as_warning;default=nodes"
2) Implement the provider factory
There is no searchrun.Register(...) function — a new backend is wired by explicit construction, following the pattern every existing provider uses (see internal/provider/localprovider/factory.go for the simplest real example).
In internal/provider/<newbackend>/factory.go:
// ConfigProvider is the config dependency this provider needs — implemented
// by configAdapter in internal/provider/all/all.go.
type ConfigProvider interface {
NewBackends() []config.NewBackend
NewBackendSlicePtr() *[]config.NewBackend
SetNewBackends([]config.NewBackend)
}
func NewFactory(cfg ConfigProvider) searchrun.ProviderFactory {
searchrun.RegisterCRUD(newbackendCRUD{cfg: cfg}) // enables web CRUD for this backend kind
return newbackendFactory{cfg: cfg}
}
type newbackendFactory struct{ cfg ConfigProvider }
// searchrun.ProviderFactory (required):
func (f newbackendFactory) FromConfig(_ searchrun.ProviderOverrides) []hosts.Backend { /* ... */ }
func (f newbackendFactory) Default(_ searchrun.ProviderOverrides) hosts.Backend { /* ... */ }
func (f newbackendFactory) BackendRows() []config.BackendRow { /* ... */ }
// searchrun.BackendConfigRegistry (required for web CRUD / schema to find this backend kind):
func (f newbackendFactory) BackendKind() string { return "newbackend" }
func (f newbackendFactory) BackendSlicePtr() any { return f.cfg.NewBackendSlicePtr() }
var (
_ searchrun.ProviderFactory = newbackendFactory{}
_ searchrun.BackendConfigRegistry = newbackendFactory{}
)
Then, in internal/provider/all/all.go:
- Add
NewBackends(),NewBackendSlicePtr(), andSetNewBackends(...)methods toconfigAdapter, each callingconfig.Get()(copy theAWSBackends/AWSBackendSlicePtr/SetAWSBackendstrio as a template). - Append
newbackend.NewFactory(adapter)to the slice returned byFactories(deps Deps).
There is no blank-import/init() auto-registration to rely on — the factory only exists in the running binary once it's explicitly added to that slice.
3) Wire search/provider behavior
Implement FromConfig/Default/BackendRows in internal/provider/<newbackend> so:
honey search --provider <newbackend>works/api/v1/searchresolves this backend
If the backend should support the Docker auto-discover second pass (see Docker auto-discover), add a DockerDiscover config.DockerDiscover field to NewBackend and wrap the returned backend with searchrun.WithDockerDiscover(backend, searchrun.MergeDockerDiscover(f.cfg.DockerDiscover(), b.DockerDiscover)) — see localprovider/factory.go for the exact pattern.
4) Schema is generated from tags
You usually do not hardcode backend field maps in internal/config/schema.go.
The schema builders reflect over config.go tags and produce:
ui_schema(dynamic forms + YAML lint)json_schema
So adding backend fields is primarily a tag/config-model change.
Schema endpoint remains: GET /api/v1/config/schema.
5) UI behavior
No manual form/lint wiring is usually needed if schema is complete:
webui/src/ConfigBackendsSection.tsxrenders backend forms dynamically fromui_schemawebui/src/RawYamlEditor.tsxlints from schema- Save YAML is blocked when diagnostics exist (warnings + errors)
6) Validation checklist
go test ./internal/searchrun ./internal/webserver ./internal/provider/...
go test ./internal/config
cd webui && npm run build
Manual smoke checks:
- search works for new provider
- config tab Add/Edit works for new backend
- YAML lint catches invalid schema fields
- Save YAML blocks while warnings/errors exist
/api/v1/config/schemacontains your backend underui_schema.backendsandjson_schema.properties.backends.properties