Skip to content

add command

Terminal window
keel add [alias|repo]

Non-interactive options:

Terminal window
keel add [alias|repo] --yes
keel add [alias|repo] --no-input

With registry refresh:

Terminal window
keel add [alias|repo] --refresh

add requires exactly one argument.

add only works inside a Keel project with:

  • go.mod
  • cmd/main.go
  • internal/ folder

If not, it returns:

keel add must be executed inside a Keel project
InputResolution
gormLooked up as alias in the official registry
github.com/acme/my-addonTreated as direct repository path (skips alias lookup)
unknown alias (for example my-addon)Treated as non-official target and asks for confirmation
  • Registry source: https://raw.githubusercontent.com/slice-soft/ss-keel-addons/main/registry.json
  • Local cache file: ~/.keel/registry.json
  • Cache TTL: 1 hour
  • --refresh bypasses fresh cache and forces network fetch
  • If network fetch fails, the CLI tries cached data first
  • If registry cannot be fetched, install can still continue by direct repository path
  • Official alias (found in registry): installs directly.
  • Non-official target: prompts for confirmation:
Install anyway? [y/N]

Only y continues. Any other answer aborts the install.

  • --yes auto-confirms this prompt and any dependency prompts.
  • --no-input disables prompts. Default-yes dependency prompts are accepted automatically, while default-no prompts for non-official addons fail fast and instruct you to rerun with --yes.

For a repository target, the CLI downloads:

https://raw.githubusercontent.com/<owner>/<repo>/main/keel-addon.json

Current support is GitHub module paths only (github.com/...).

The CLI parses this structure:

{
"name": "my-addon",
"version": "0.1.0",
"description": "Description",
"repo": "github.com/your-org/my-addon",
"depends_on": ["jwt"],
"steps": [
{ "type": "go_get", "package": "github.com/your-org/my-addon@v0.1.0" },
{ "type": "env", "key": "MY_ADDON_KEY", "example": "value", "description": "Optional note" },
{ "type": "main_import", "path": "github.com/your-org/my-addon" },
{ "type": "main_code", "anchor": "before_modules", "guard": "myaddon.Setup(", "code": "myaddon.Setup(app, appLogger)" },
{ "type": "create_provider_file", "filename": "cmd/setup_myaddon.go", "guard": "func setupMyAddon(", "content": "package main\n\n// ..." },
{ "type": "note", "message": "Next step: wire a protected /api/me route" }
]
}

depends_on is optional. When present, the CLI checks whether each listed alias is already installed. Missing dependencies trigger a default-yes prompt so the CLI can install them before the requested addon. For scripted runs, use --yes to auto-approve all prompts, or --no-input to accept the default dependency answer without blocking. For example, ss-keel-oauth declares "depends_on": ["jwt"] because it requires ss-keel-jwt to sign tokens.

Step typeWhat it does
go_getRuns go get <package> (adds @latest if version is omitted)
envAppends KEY=example into .env and .env.example if the key does not exist
main_importAdds import path to cmd/main.go if missing
main_codeInserts code into cmd/main.go; guard avoids duplicates; anchor accepts "before_listen" or "before_modules"
create_provider_fileCreates a new Go file (e.g. cmd/setup_gorm.go) with a self-contained setup function, keeping cmd/main.go clean; guard checks for the function signature before creating
notePrints a post-install note after wiring and go mod tidy finish

Unknown step types fail the install.

Instead of bloating cmd/main.go with initialization code, addons use this step to generate a dedicated file. For example, keel add gorm creates cmd/setup_gorm.go:

// cmd/setup_gorm.go — generated by keel add gorm
package main
func setupGorm(app *core.App, log *logger.Logger) *database.DBinstance {
dbConfig := config.MustLoadConfig[database.Config]()
dbConfig.Logger = log
db, err := database.New(dbConfig)
if err != nil {
log.Error("failed to initialize database: %v", err)
}
app.RegisterHealthChecker(database.NewHealthChecker(db))
return db
}

And then a main_code step adds the call into cmd/main.go:

db := setupGorm(app, appLogger)
defer db.Close()

This keeps each addon’s wiring isolated and cmd/main.go readable regardless of how many addons are installed.

  • Steps run in order.
  • Then CLI runs go mod tidy.
  • Finally, any note steps are printed.
  • If go mod tidy fails, the CLI prints a warning but does not fail the full install.
  • If dependency prompts are accepted, their installs run before the target addon and share the same final tidy pass.
  • In non-interactive runs, dependency prompts use their default answer instead of waiting on stdin.

Install official addon by alias:

Terminal window
keel add gorm

Install MongoDB addon by alias:

Terminal window
keel add mongo

Install community addon by repo:

Terminal window
keel add github.com/acme/ss-keel-feature-flags

Force refresh alias registry:

Terminal window
keel add gorm --refresh

Install OAuth and auto-accept its JWT dependency in CI:

Terminal window
keel add oauth --yes

keel add runs go get <addon>@latest under the hood. In addition to the addon itself, this can:

  • Update the go directive in go.mod (e.g. go 1.25.0 → go 1.25.7)
  • Add or upgrade indirect dependencies

This is normal Go module behaviour. Keel prints a short summary when the go directive changes or new indirect dependencies are added, so you can spot unexpected churn before committing.

If you want a narrower diff, pin the addon to a specific version by editing go.mod manually after install.

  • keel add must be executed inside a Keel project
  • could not fetch addon registry: ...
  • only github.com repos are supported (got "...")
  • <repo> does not have a keel-addon.json — it may not be a Keel addon
  • invalid keel-addon.json in <repo>: ...
  • step "<type>" failed: ...