Internal Architecture of the internal/cli Package in JetBrains/go-modern-guidelines

The internal/cli package implements a thin command-line front-end that parses arguments, dispatches to sub-commands, and delegates guideline resolution to specialized internal packages.

The internal/cli package serves as the primary user interface for the go-modern-guidelines tool developed by JetBrains. Understanding the internal architecture of the internal/cli package reveals a deliberately simple design that prioritizes testability and clear separation of concerns. The entire implementation resides in a single file, internal/cli/cli.go, supported by comprehensive unit tests in internal/cli/cli_test.go.

Architectural Layers

The architecture is organized into distinct functional layers, each handling specific aspects of command-line interaction.

Entry Point and Command Dispatch

The entry point is the exported Run function, defined as func Run(args []string, stdout io.Writer) error in internal/cli/cli.go. This function receives command-line arguments and an output writer, then dispatches to appropriate handlers based on the first argument. A simple switch statement routes to runList, runExplain, or utility functions like printUsage and printVersion depending on whether the user invoked the list, explain, or help/version commands.

Sub-Command Implementations

Each sub-command manages its own flag.FlagSet to prevent option leakage between operations. The runList function creates a flag set accepting --go-version and --file-path parameters, then calls goversion.Resolve to determine the target Go version before formatting output via guidelines.ListText. The runExplain function uses the custom stringListFlag type to collect one or more guideline IDs, then retrieves detailed descriptions through guidelines.ExplainText.

Flag Handling Infrastructure

Centralized helpers reduce boilerplate and ensure consistent behavior across commands. The newFlagSet function creates preconfigured flag sets with standardized naming, while parseFlagSet normalizes parsing errors and automatically surfaces help text when requested. These utilities capture help output and surface parsing errors without exposing implementation details to the sub-command logic.

Utility Functions and Types

Supporting functions include detectedVersion for identifying the build's Go version, printUsage for displaying static help text, and printVersion for outputting the tool's version. The stringListFlag type implements flag.Value to enable repeated or CSV-style flag values, supporting complex query patterns required by the explain command.

Execution Flow

The typical execution path begins when Run receives arguments and an output writer. If no arguments are provided, the system immediately invokes printUsage. When a valid command is detected, the dispatcher routes to the appropriate handler. Both runList and runExplain follow a consistent three-phase pattern: instantiate flags using newFlagSet, parse input via parseFlagSet, resolve dependencies through internal/goversion or internal/guidelines, and return formatted text to the provided writer.

External Dependencies

The package maintains minimal coupling by relying on two internal dependencies. The internal/goversion package resolves version strings from command-line flags, filesystem paths, or defaults to the latest known version. The internal/guidelines package supplies domain logic through ListText and ExplainText functions, ensuring the CLI layer remains strictly concerned with presentation and input validation.

Usage Example

Developers integrate the package by invoking the Run function with appropriate arguments. The following driver program demonstrates common operations against the internal/cli package API:

package main

import (
	"os"

	"github.com/JetBrains/go-modern-guidelines/internal/cli"
)

func main() {
	// Example 1: Show usage (no arguments)
	_ = cli.Run([]string{}, os.Stdout)

	// Example 2: List guidelines for Go 1.22
	_ = cli.Run([]string{"list", "--go-version", "1.22"}, os.Stdout)

	// Example 3: Explain a specific guideline
	_ = cli.Run([]string{"explain", "--guideline-id", "G001"}, os.Stdout)

	// Example 4: Print the tool’s own version
	_ = cli.Run([]string{"--version"}, os.Stdout)
}

This pattern enables programmatic invocation of CLI functionality while maintaining clean separation between the command layer and business logic.

Summary

  • The internal/cli package provides a thin wrapper around core functionality, implementing only presentation logic in internal/cli/cli.go.
  • The entry point Run acts as a central dispatcher, routing to runList, runExplain, or utility functions based on the first argument.
  • Each sub-command maintains its own flag.FlagSet using helpers like newFlagSet and parseFlagSet for consistent error handling.
  • The custom stringListFlag type enables flexible repeated flag parsing for complex guideline queries.
  • Dependencies on internal/goversion and internal/guidelines ensure the CLI remains focused on I/O operations while delegating domain logic to specialized packages.

Frequently Asked Questions

What is the main entry point of the internal/cli package?

The Run function serves as the sole public entry point, defined as func Run(args []string, stdout io.Writer) error in internal/cli/cli.go. This design allows both production code and test suites to inject arguments and capture output through the writer interface, facilitating deterministic testing without subprocess overhead.

How does the internal/cli package handle command-line flags?

Each sub-command constructs its own flag.FlagSet using the newFlagSet helper, ensuring isolation between commands. The parseFlagSet utility normalizes error handling by either printing help text for usage errors or returning clean error strings, while the custom stringListFlag type supports repeated or comma-separated values for complex inputs.

Which internal packages does internal/cli depend on?

The package depends exclusively on internal/goversion for resolving target Go versions from flags or files, and internal/guidelines for retrieving guideline content. This dependency structure maintains a strict separation between the presentation layer and domain logic, keeping the CLI implementation lightweight and focused.

Where is the internal/cli package located in the repository?

All implementation logic resides in internal/cli/cli.go, with corresponding tests in internal/cli/cli_test.go. These two files constitute the complete architecture, making the package easy to navigate and modify without cross-referencing multiple directories.

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 →