Plugins
TerraCi is built as a plugin-first system. Every feature — pipeline generation, cost estimation, policy checks, MR comments — is a plugin. You can add your own plugins to integrate with any tool or service your team uses.
What Can Plugins Do?
| Plugin Type | What It Adds | Example Use Cases |
|---|---|---|
| CLI Command | New terraci <command> subcommand | Slack notifications, custom reports, infra audits |
| Pipeline Step | Jobs/steps injected into generated CI pipelines | Security scans, compliance checks, deployment gates |
| CI Provider | Support for a new CI system (beyond GitLab/GitHub) | Bitbucket Pipelines, Jenkins, CircleCI |
| Init Wizard Field | Configuration fields in terraci init TUI | Custom plugin settings, team-specific defaults |
Quick Start
Build a custom TerraCi with your plugin in 3 steps:
# 1. Write your plugin (see guides below)
# 2. Build a custom binary
xterraci build --with github.com/your-org/terraci-plugin-slack
# 3. Use it
./terraci slack --channel #deploysArchitecture
┌──────────────────────────┐
│ TerraCi Core │
│ │
│ discovery → parser → │
│ graph → pipeline IR │
└──────────┬───────────────┘
│
┌────────────────┼────────────────┐
│ │ │
┌─────┴─────┐ ┌─────┴─────┐ ┌─────┴─────┐
│ Built-in │ │ Built-in │ │ Your │
│ Plugins │ │ Plugins │ │ Plugin │
│ │ │ │ │ │
│ gitlab │ │ cost │ │ slack │
│ github │ │ policy │ │ jira │
│ git │ │ summary │ │ vault │
│ │ │ tfupdate │ │ ... │
└────────────┘ └────────────┘ └───────────┘Plugins are compiled into the binary. There is no runtime plugin loading — this means zero overhead and full type safety.
Guides
CLI Command Plugin
Add a new terraci <command>. The most common plugin type — perfect for notifications, reports, integrations.
Pipeline Step Plugin
Inject custom jobs or steps into generated CI pipelines. Use for security scans, approval gates, or post-deploy hooks.
CI Provider Plugin
Add support for a new CI system. Implement pipeline generation, environment detection, and MR/PR comments.
Init Wizard Plugin
Add configuration fields to the terraci init interactive wizard. Users configure your plugin through a TUI form.
Built-in Plugins
| Plugin | Capabilities | Config |
|---|---|---|
| git | ChangeDetection, Preflight | Always active |
| gitlab | Generator, EnvDetector, Comments, Preflight, Init | config/gitlab |
| github | Generator, EnvDetector, Comments, Preflight, Init | config/github |
| summary | Command, Pipeline, Init | Enabled by default |
| cost | Command, Pipeline, Runtime, Preflight, Init | config/cost |
| policy | Command, Pipeline, Runtime, Preflight, Version, Init | config/policy |
| tfupdate | Command, Pipeline, Runtime, Preflight, Init | config/tfupdate |
Plugin Basics
Registration
Every plugin registers itself in init():
package myplugin
import (
"github.com/edelwud/terraci/pkg/plugin"
"github.com/edelwud/terraci/pkg/plugin/registry"
)
func init() {
registry.Register(&Plugin{
BasePlugin: plugin.BasePlugin[*Config]{
PluginName: "myplugin",
PluginDesc: "What my plugin does",
EnableMode: plugin.EnabledExplicitly,
DefaultCfg: func() *Config { return &Config{} },
IsEnabledFn: func(cfg *Config) bool {
return cfg != nil && cfg.Enabled
},
},
})
}
type Plugin struct {
plugin.BasePlugin[*Config]
}
type Config struct {
Enabled bool `yaml:"enabled"`
}Users configure your plugin in .terraci.yaml:
plugins:
myplugin:
enabled: trueActivation Policies
| Policy | Behavior | Used by |
|---|---|---|
EnabledAlways | Always active, no config needed | git |
EnabledWhenConfigured | Active when config section exists | gitlab, github |
EnabledByDefault | Active unless enabled: false | summary |
EnabledExplicitly | Requires explicit opt-in | cost, policy, update |
Lifecycle
Register → Configure → Preflight → Freeze → Execute- Register —
init()runs at import time - Configure — framework decodes
plugins.<key>from YAML - Preflight — cheap validation (no network, no heavy state)
- Freeze — context becomes immutable
- Execute — commands lazily build runtime as needed
AppContext
Every capability receives *plugin.AppContext with:
ctx.WorkDir() // project root directory
ctx.ServiceDir() // resolved .terraci directory (absolute path)
ctx.Config() // full TerraCi configuration (defensive copy)
ctx.Version() // TerraCi version string
ctx.Reports() // shared report registry for plugin communicationBuilding
# From published module
xterraci build --with github.com/your-org/terraci-plugin-slack
# From local directory during development
xterraci build --with github.com/your-org/plugin=./my-plugin
# Exclude built-in plugins you don't need
xterraci build --without cost --without policy
# Pin specific version
xterraci build --with github.com/your-org/plugin@v1.2.0See Also
- examples/external-plugin — working example
- Plugin System Overview — architecture deep dive
- xterraci CLI — build custom binaries