CLI Commands
Tako apps are also CLI apps. When your binary is invoked with arguments, the CLI Kernel takes over and routes to the matching command. No TUI starts — just the command output. This is how myapp help, myapp version, and myapp plugin:list all work.
Built-in Commands
The framework registers these automatically in Application.Boot():
| Command | Description |
|---|---|
help | Prints the ASCII logo and all registered commands |
version | Prints Go runtime info and framework version |
status | Basic memory and runtime statistics |
plugin:list | Lists all registered plugins with their status and load times |
inspect | Opens the live interactive profiler/inspector TUI |
dev | Hot-reload watcher (non-production builds only) |
build | Production binary compilation (non-production builds only) |
Registering a Custom Command
Implement the cli.Command interface:
type Command interface {
Name() string
Description() string
DefineFlags(fs *flag.FlagSet)
Execute(ctx *cli.Context, args []string) error
}Then register it before tako.Run():
app.CliRegistry().Register(&MyCommand{})
tako.Run(app)Or register from within a plugin's OnInit:
func (p *Plugin) OnInit(ctx *tako.Context) error {
var cliReg *cli.Registry
if err := ctx.Container().Make(&cliReg); err != nil {
return err
}
cliReg.Register(&MigrateCommand{db: p.db})
return nil
}A Complete Command Example
package commands
import (
"flag"
"fmt"
"github.com/takoterm/tako/internal/cli"
)
type ExportCommand struct {
format string
output string
}
func (c *ExportCommand) Name() string {
return "export"
}
func (c *ExportCommand) Description() string {
return "Export data to a file."
}
func (c *ExportCommand) DefineFlags(fs *flag.FlagSet) {
fs.StringVar(&c.format, "format", "json", "Output format: json, csv, tsv")
fs.StringVar(&c.output, "output", "export.json", "Output file path")
}
func (c *ExportCommand) Execute(ctx *cli.Context, args []string) error {
ctx.Info(fmt.Sprintf("Exporting in %s format to %s", c.format, c.output))
// ... do the work ...
ctx.Success("Export complete.")
return nil
}Usage:
myapp export --format csv --output data.csvCommand Namespacing
Group related commands with a colon namespace. They appear grouped in help output:
func (c *MigrateRunCommand) Name() string { return "migrate:run" }
func (c *MigrateRollbackCommand) Name() string { return "migrate:rollback" }
func (c *MigrateStatusCommand) Name() string { return "migrate:status" } migrate
migrate:rollback Roll back the last migration batch.
migrate:run Run all pending migrations.
migrate:status Show migration status.CLI Context
The cli.Context passed to Execute has more than just the tako.Context — it includes output helpers with colored formatting:
func (c *MyCommand) Execute(ctx *cli.Context, args []string) error {
ctx.Info("Starting process...") // neutral information
ctx.Warn("This might take a while") // yellow warning
ctx.Error("Something went wrong") // red error message
ctx.Success("All done!") // green success
// Access the framework context for services
logger := ctx.Logger()
config := ctx.Config()
return nil
}Mounting a TUI from a Command
A command can launch a full TUI view — this is how myapp inspect works:
func (c *InspectCommand) Execute(ctx *cli.Context, args []string) error {
// Create your Bubble Tea model/layout
inspectorView := inspector.NewInspectorView()
// Tell the CLI context to run a TUI
ctx.RunUI(inspectorView)
return nil
}ctx.RunUI(view) sets the view on the context. The CLI Kernel detects this and starts a Bubble Tea program with the provided view, then exits normally when done. The main application TUI is not affected.
CLI Middleware
Middleware wraps all command execution. Use it for cross-cutting concerns like logging, authentication, or rate limiting:
// Register middleware on the CLI registry
app.CliRegistry().Use(func(next cli.CommandFunc) cli.CommandFunc {
return func(ctx *cli.Context, args []string) error {
ctx.Logger().Info("Command started", "name", "?")
err := next(ctx, args)
if err != nil {
ctx.Logger().Error("Command failed", "err", err)
}
return err
}
})Middleware is applied in reverse registration order — the last Use call is the outermost wrapper. This is the classic onion model.
Flag Parsing
Flags are parsed with Go's standard flag.FlagSet. Tako adds Laravel Artisan-style help output:
myapp export --help
Description:
Export data to a file.
Usage:
export [options]
Options:
--format[=FORMAT] Output format: json, csv, tsv
--output[=OUTPUT] Output file path [default: "export.json"]
-h, --help Display help for the given command.You've reached the end of the core documentation. For a full index of all topics, see the table below, or browse the
docs/folder directly.
Quick Reference: All Documentation
| Topic | File |
|---|---|
| Architecture overview | 01-overview.md |
| Installation | 02-getting-started/01-installation.md |
| App initialization | 02-getting-started/02-initialization.md |
| Your first plugin | 02-getting-started/03-first-plugin.md |
| Service Container | 03-core-concepts/01-service-container.md |
| Event Bus | 03-core-concepts/02-event-bus.md |
| Hook Registry | 03-core-concepts/03-hooks.md |
| Keybindings & Focus Stack | 03-core-concepts/04-keybindings.md |
| Config & Storage | 03-core-concepts/05-config-storage.md |
| Stack Guards | 03-core-concepts/06-stack-guards.md |
| Typed Event Bus | 03-core-concepts/02-event-bus.md |
| UI Adapters (Bubble Tea + custom) | 05-ui/01-adapters.md |
| Layouts & Zones | 05-ui/02-layouts-zones.md |
| Profiler Integration | 05-ui/03-profiler-integration.md |
| Plugin basics | 06-plugins/01-plugin-basics.md |
| Plugin lifecycle | 06-plugins/02-plugin-lifecycle.md |
| Plugin dependencies | 06-plugins/03-plugin-dependencies.md |
| Inspector, Profiler, Hot Reload | 07-devtools/01-inspector.md |
| CLI Commands & Middleware | 08-cli/01-commands.md ← you are here |
