| type | Package Documentation |
|---|---|
| title | CoreCLI runtime — lifecycle, signals, daemon mode |
| description | The CLI runtime layer — Init/Main lifecycle, Options, signal handling, execution modes, the Daemon process helper, and exit-code errors |
| repo | core/cli |
| module | dappco.re/go/cli |
The runtime layer stands up a *core.Core for the process, runs command setup, executes the requested command, and shuts down cleanly. Source: go/pkg/cli/app.go, runtime.go, service.go, daemon.go, daemon_process.go, errors.go, io.go, log.go.
cli.Main is the whole main function for a Core binary. It initialises the runtime with framework translations, registers command setups, executes, and exits with the right code:
func main() {
cli.WithAppName("core")
cli.Main(
cli.WithCommands("config", config.AddConfigCommands),
cli.WithCommands("doctor", doctor.AddDoctorCommands),
)
}MainWithLocales is the same with extra translation sources:
locales := []cli.LocaleSource{cli.WithLocales(embeddedLocales, "locales")}
cli.MainWithLocales(locales, doctor.AddDoctorCommands)Main recovers panics (logs the stack, shuts down, exits via Fatal), sets a banner of AppName + SemVer() on the Core CLI, and honours *ExitError codes from failed execution.
For finer control, the pieces Main composes are public:
r := cli.Init(cli.Options{AppName: "core"})
if !r.OK { panic(r.Error()) }
defer cli.Shutdown()
c := cli.Core() // the underlying *core.Core
r = cli.Execute() // parse args and run the matching command
ctx := cli.Context() // runtime context, cancelled on signalRun(ctx) and RunWithTimeout(timeout) support long-running service use.
type Options struct {
AppName string
Version string
Services []core.Service // additional services to register
I18nSources []LocaleSource // additional translation sources
// OnReload is called when SIGHUP is received (daemon mode).
// Leave nil to ignore SIGHUP.
OnReload func() error
}Init creates the Core instance via the package's own Register(c) service (never core.WithCli(), which would double-register the CLI primitive), then registers a signal service and any extra services.
Build-time variables set via ldflags, composed by SemVer() into a SemVer 2.0.0 string:
// go build -ldflags="-X dappco.re/go/cli/pkg/cli.AppVersion=1.2.0 \
// -X dappco.re/go/cli/pkg/cli.BuildCommit=df94c24 \
// -X dappco.re/go/cli/pkg/cli.BuildDate=2026-02-06 \
// -X dappco.re/go/cli/pkg/cli.BuildPreRelease=dev.8"
// SemVer() -> "1.2.0-dev.8+df94c24.2026-02-06"
var AppVersion, BuildCommit, BuildDate, BuildPreReleaseThe same values are exposed as actions: cli.version, cli.app_name, cli.build_info (registered in service.go).
daemon.go detects how the process is being run:
mode := cli.DetectMode()
// cli.ModeDaemon when CORE_DAEMON=1
// cli.ModePipe when stdout is not a terminal (colours disabled)
// cli.ModeInteractive otherwiseTTY probes: IsTTY(), IsStdinTTY(), IsStderrTTY() (backed by internal/term, a thin wrapper over golang.org/x/term exposing IsTerminal and TerminalSize).
daemon_process.go provides a background-process harness with PID file and HTTP health probes:
d := cli.NewDaemon(cli.DaemonOptions{
PIDFile: "/var/run/app.pid",
HealthAddr: ":8090", // empty string disables the server
HealthPath: "/healthz", // liveness
ReadyPath: "/readyz", // readiness
HealthCheck: func() bool { return true },
})
r := d.Start(ctx)
defer d.Stop(ctx)StopPIDFile(pidFile, timeout) stops a previously started daemon by its PID file.
errors.go wraps the core error primitives for CLI use:
| Function | Purpose |
|---|---|
Err(format, args...) |
Failed core.Result from a format string |
Wrap(err, msg) |
Wrap with message; core.Ok(nil) when err is nil |
WrapVerb(err, verb, subject) |
i18n grammar: "Failed to load config: …" |
WrapAction(err, verb) |
i18n grammar: "Failed to connect: …" |
Is, As, Join |
Re-exports of the core error-tree helpers |
Exit(code, err) |
Result carrying an *ExitError |
Fatal(failure), Fatalf, FatalWrap, FatalWrapVerb |
Print and exit |
ExitError{Code, Err} is honoured by Main: a failed Execute whose value unwraps to an ExitError exits with that code.
io.go lets tests and hosts swap the standard streams: SetStdin(r), SetStdout(w), SetStderr(w). log.go forwards to the core logger: LogDebug, LogInfo, LogWarn, LogError, LogSecurity, LogSecurityf.
| File | Contents |
|---|---|
go/pkg/cli/app.go |
Main, MainWithLocales, WithAppName, WithLocales, SemVer, build vars |
go/pkg/cli/runtime.go |
Init, Options, Core, Execute, Run, Context, Shutdown, signal service |
go/pkg/cli/service.go |
CLI service registration, cli.version / cli.app_name / cli.build_info actions |
go/pkg/cli/daemon.go |
Mode, DetectMode, TTY probes |
go/pkg/cli/daemon_process.go |
Daemon, DaemonOptions, StopPIDFile |
go/pkg/cli/errors.go |
Err, Wrap*, ExitError, Exit, Fatal* |
go/pkg/cli/io.go |
SetStdin, SetStdout, SetStderr |
go/pkg/cli/log.go |
Log* forwarding to the core logger |
go/internal/term/term.go |
IsTerminal, TerminalSize |