How Commands Are Organized in the gastownhall/gastown cmd Directory

The gastown CLI organizes commands into seven logical groups using the Cobra framework, with the root command defined in internal/cmd/root.go and sub-commands auto-registered via Go's init() functions in modular files.

The gastownhall/gastown project structures its command-line interface using a clean, modular approach that leverages the Cobra library. All CLI logic resides in the internal/cmd/ directory, where each functional area is encapsulated in its own source file and assigned to one of seven semantic groups. This architecture ensures that the gt binary presents a logically organized help interface while maintaining extensible, maintainable code.

Root Command and Group Architecture

The entry point for all CLI operations is internal/cmd/root.go, which instantiates a rootCmd named gt. This file defines seven logical group constants that control the order and categorization of commands in the help output.

The groups are declared between lines 33 and 55 in root.go and attached to the root command via rootCmd.AddGroup(). Each sub-command then sets its GroupID field to associate itself with one of these categories.

The Seven Command Groups

The root.go file organizes commands into the following semantic categories:

  • GroupWork – Work Management: Commands that schedule, execute, or query work (e.g., gt wl, gt up, gt start).
  • GroupAgents – Agent Management: Commands for starting, listing, or interacting with AI agents (e.g., gt role, gt polecat).
  • GroupComm – Communication: Commands for inter-agent messaging (gt nudge, gt mail).
  • GroupServices – Services: Long-running background services (gt refinery, gt reaper).
  • GroupWorkspace – Workspace: Commands that manipulate the Gas Town workspace (gt init, gt rig).
  • GroupConfig – Configuration: Settings-related commands (gt config, gt plugin).
  • GroupDiag – Diagnostics: Debugging and inspection commands (gt version, gt doctor).

When users run gt --help, Cobra renders commands under these group headings, making it easy to discover related functionality.

Command Registration Pattern

Each file in internal/cmd/ follows a consistent pattern to wire commands into the hierarchy:

  1. Define a package-level cobra.Command variable (typically named <name>Cmd).
  2. Set the GroupID field to one of the constants exported from root.go.
  3. Configure flags in an init() function.
  4. Register the command using rootCmd.AddCommand() or attach it to a parent command.

Because Go automatically executes init() functions when the package loads, simply importing the cmd package in main.go registers all commands without manual bookkeeping.

// Example from internal/cmd/wl.go
var wlCmd = &cobra.Command{
    Use:     "wl",
    GroupID: GroupWork,               // ← belongs to the “Work Management” group
    Short:   "Wasteland federation commands",
    RunE:    requireSubcommand,
}

func init() {
    rootCmd.AddCommand(wlCmd)    // ← registers with the root
}

Sub-commands follow the same pattern, attaching to their parent via parentCmd.AddCommand(). For example, in wl.go, the wl join sub-command is wired in the same init() block:

func init() {
    wlJoinCmd.Flags().StringVar(&wlJoinHandle, "handle", "", "Rig handle for registration")
    wlCmd.AddCommand(wlJoinCmd)  // ← sub-command attached to wl
    rootCmd.AddCommand(wlCmd)    // ← wl attached to the root
}

File Organization and Key Source Files

The internal/cmd/ directory uses a flat structure where each functional domain owns its file. This separation of concerns allows developers to locate logic quickly and prevents merge conflicts in monolithic files.

The entry point in main.go simply imports the cmd package and calls rootCmd.Execute(), relying on the automatic registration via init() functions:

// main.go
func main() {
    if err := rootCmd.Execute(); err != nil {
        os.Exit(1)
    }
}

Practical Example: Adding a New Command

To extend the CLI, create a new file in internal/cmd/ following the established pattern. Here is a complete example that adds a gt greet command under the Diagnostics group:

// internal/cmd/greet.go
package cmd

import (
    "fmt"
    "github.com/spf13/cobra"
)

var greetCmd = &cobra.Command{
    Use:     "greet <name>",
    GroupID: GroupDiag,               // puts it under Diagnostics
    Short:   "Print a friendly greeting",
    Args:    cobra.ExactArgs(1),
    RunE: func(cmd *cobra.Command, args []string) error {
        fmt.Printf("Hello, %s! 👋\n", args[0])
        return nil
    },
}

func init() {
    rootCmd.AddCommand(greetCmd) // registers with the root
}

After rebuilding, gt --help displays greet under the Diagnostics section, and gt greet Alice executes the command.

Summary

  • The root command in internal/cmd/root.go defines seven logical groups (GroupWork, GroupAgents, etc.) that organize the help output.
  • Each command file uses Go's init() function to auto-register itself with rootCmd.AddCommand(), eliminating manual wiring.
  • The GroupID field assigns commands to semantic categories, ensuring consistent CLI documentation.
  • The modular file structure allows adding new commands by creating a single file without modifying core logic.

Frequently Asked Questions

What CLI framework does gastown use?

The gastown project uses the Cobra framework for Go. Cobra provides the command structure, flag parsing, and help generation used throughout the internal/cmd/ directory.

How do I add a new command to the gastown CLI?

Create a new file in internal/cmd/, define a cobra.Command variable, set the appropriate GroupID from root.go, and call rootCmd.AddCommand() inside an init() function. The command automatically appears in the help output under its designated group.

Why are commands organized into groups?

The group constants (GroupWork, GroupAgents, etc.) control the visual organization of gt --help. This taxonomy keeps related commands together, making the interface discoverable for users and maintainable for developers who know exactly which file contains which feature.

Where is the entry point for the gastown CLI?

The entry point is the main() function in the repository root (typically main.go or cmd/gt/main.go). This function imports the internal/cmd package and calls rootCmd.Execute(), which triggers Cobra's command routing and invokes the appropriate RunE function.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →