Skip to content

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():

CommandDescription
helpPrints the ASCII logo and all registered commands
versionPrints Go runtime info and framework version
statusBasic memory and runtime statistics
plugin:listLists all registered plugins with their status and load times
inspectOpens the live interactive profiler/inspector TUI
devHot-reload watcher (non-production builds only)
buildProduction binary compilation (non-production builds only)

Registering a Custom Command

Implement the cli.Command interface:

go
type Command interface {
    Name() string
    Description() string
    DefineFlags(fs *flag.FlagSet)
    Execute(ctx *cli.Context, args []string) error
}

Then register it before tako.Run():

go
app.CliRegistry().Register(&MyCommand{})
tako.Run(app)

Or register from within a plugin's OnInit:

go
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

go
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:

bash
myapp export --format csv --output data.csv

Command Namespacing

Group related commands with a colon namespace. They appear grouped in help output:

go
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:

go
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:

go
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:

go
// 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:

bash
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

TopicFile
Architecture overview01-overview.md
Installation02-getting-started/01-installation.md
App initialization02-getting-started/02-initialization.md
Your first plugin02-getting-started/03-first-plugin.md
Service Container03-core-concepts/01-service-container.md
Event Bus03-core-concepts/02-event-bus.md
Hook Registry03-core-concepts/03-hooks.md
Keybindings & Focus Stack03-core-concepts/04-keybindings.md
Config & Storage03-core-concepts/05-config-storage.md
Stack Guards03-core-concepts/06-stack-guards.md
Typed Event Bus03-core-concepts/02-event-bus.md
UI Adapters (Bubble Tea + custom)05-ui/01-adapters.md
Layouts & Zones05-ui/02-layouts-zones.md
Profiler Integration05-ui/03-profiler-integration.md
Plugin basics06-plugins/01-plugin-basics.md
Plugin lifecycle06-plugins/02-plugin-lifecycle.md
Plugin dependencies06-plugins/03-plugin-dependencies.md
Inspector, Profiler, Hot Reload07-devtools/01-inspector.md
CLI Commands & Middleware08-cli/01-commands.md ← you are here