{
  "id": "go-cli",
  "name": "Go CLI/TUI: Cobra + Bubble Tea + GoReleaser",
  "use_cases": [
    "Shipped command-line products",
    "infrastructure administration tools",
    "terminal dashboards"
  ],
  "choose_when": [
    "Want compiled distribution with Go ecosystem access",
    "Command structure and terminal UX matter more than tight low-level control"
  ],
  "avoid_when": [
    "Primarily a short disposable script",
    "Host SDK or native UI framework mandates another language",
    "Strict no-GC constraints"
  ],
  "tools": [
    {
      "job": "Command parsing",
      "default": "Cobra",
      "alternatives": [
        "flag for a small single command"
      ],
      "reason": "Command/help/completion structure plus event-driven terminal UI.",
      "limits": "Keep noninteractive and machine-readable modes; test TTY absence, cancellation and terminal restoration.",
      "source_urls": [
        "https://github.com/spf13/cobra",
        "https://github.com/charmbracelet/bubbletea",
        "https://pkg.go.dev/flag"
      ]
    },
    {
      "job": "Terminal UI",
      "default": "Bubble Tea only for interactive screens",
      "alternatives": [
        "Line-oriented output when no interactive screen is needed"
      ],
      "reason": "Command/help/completion structure plus event-driven terminal UI.",
      "limits": "Keep noninteractive and machine-readable modes; test TTY absence, cancellation and terminal restoration.",
      "source_urls": [
        "https://github.com/spf13/cobra",
        "https://github.com/charmbracelet/bubbletea",
        "https://pkg.go.dev/flag"
      ]
    },
    {
      "job": "HTTP client",
      "default": "net/http Client",
      "alternatives": [],
      "reason": "Standard client with contexts and transport reuse.",
      "limits": "Set timeouts, bound responses and close bodies; retry only when operation semantics allow.",
      "source_urls": [
        "https://pkg.go.dev/net/http"
      ]
    },
    {
      "job": "Persistence and migrations",
      "default": "None for stateless tools",
      "alternatives": [
        "Use service API for shared state"
      ],
      "reason": "Avoid introducing a database into a command wrapper.",
      "limits": "Local durable state requires a separately selected storage/schema policy; never assume flat-file writes are atomic.",
      "source_urls": [
        "https://pkg.go.dev/os"
      ]
    },
    {
      "job": "Configuration",
      "default": "Typed settings loaded with os.LookupEnv",
      "alternatives": [
        "flag for small command surfaces"
      ],
      "reason": "Explicit startup validation and standard structured logs.",
      "limits": "Define precedence; reject malformed required values; redact secrets. Environment access alone is not validation or secret management.",
      "source_urls": [
        "https://pkg.go.dev/os",
        "https://pkg.go.dev/flag",
        "https://pkg.go.dev/log/slog"
      ]
    },
    {
      "job": "Application logging",
      "default": "log/slog",
      "alternatives": [],
      "reason": "Explicit startup validation and standard structured logs.",
      "limits": "Define precedence; reject malformed required values; redact secrets. Environment access alone is not validation or secret management.",
      "source_urls": [
        "https://pkg.go.dev/os",
        "https://pkg.go.dev/flag",
        "https://pkg.go.dev/log/slog"
      ]
    },
    {
      "job": "Tests and static checks",
      "default": "testing; go vet; race detector; govulncheck",
      "alternatives": [],
      "reason": "Standard toolchain feedback plus exercised concurrency and known-vulnerability checks.",
      "limits": "Race detector requires supported target/toolchain and exercised code; no scanner proves absence of vulnerabilities.",
      "source_urls": [
        "https://pkg.go.dev/testing",
        "https://go.dev/doc/articles/race_detector",
        "https://golangci-lint.run/docs/welcome/quick-start/",
        "https://go.dev/doc/security/vuln/"
      ]
    },
    {
      "job": "Durable work",
      "default": "Delegate long jobs to a service; persist its job ID",
      "alternatives": [
        "River-backed Go service"
      ],
      "reason": "Work survives the terminal process only through an explicit durable owner.",
      "limits": "A goroutine or TUI background command dies with the process; reconnection needs a stable job identity.",
      "source_urls": [
        "https://riverqueue.com/docs/transactional-enqueueing",
        "https://github.com/charmbracelet/bubbletea"
      ]
    },
    {
      "job": "Distribution",
      "default": "GoReleaser",
      "alternatives": [
        "Manual go build for one internal target"
      ],
      "reason": "Target builds and release artifact automation.",
      "limits": "Review generated release actions, supported targets, signing and updater policy. cgo can complicate cross-building.",
      "source_urls": [
        "https://goreleaser.com/getting-started/quick-start/"
      ]
    },
    {
      "job": "Machine-readable output",
      "default": "encoding/json/v2 on a supporting pinned Go toolchain",
      "alternatives": [
        "encoding/json for established output contracts or older supported toolchains"
      ],
      "reason": "Stable JSON output lets scripts consume commands without parsing terminal text",
      "limits": "Add an explicit --json/output mode and document schema/exit codes; reserve stdout for results, stderr for diagnostics, and disable interactive/color output for pipelines. Confirm API availability on the pinned Go version; v2 changes encoding/decoding defaults, so test schema/null/omission compatibility before migrating.",
      "source_urls": [
        "https://pkg.go.dev/encoding/json",
        "https://pkg.go.dev/encoding/json/v2"
      ]
    },
    {
      "job": "Cancellation and shutdown",
      "default": "signal.NotifyContext",
      "alternatives": [
        "Preserve an existing compatible project choice"
      ],
      "reason": "User interrupts should cancel outbound work and leave terminal/files usable",
      "limits": "Propagate cancellation through work; bound cleanup time and test interrupts during writes. Avoid adding an async runtime to a synchronous Rust CLI solely for signals.",
      "source_urls": [
        "https://pkg.go.dev/os/signal"
      ]
    }
  ],
  "setup_steps": [
    "Start in a source checkout; go mod init example.com/tool using its intended module path.",
    "Run go get github.com/spf13/cobra; resolve a supported Bubble Tea release only if a TUI is required.",
    "Build cmd/tool with injectable I/O, configuration validation, stable exit codes and explicit noninteractive behavior.",
    "Write command tests covering malformed input, stdout/stderr, cancellation and safe retries; use isolated temporary paths.",
    "Run goreleaser init, then review and pin the generated configuration and target matrix. No setup or publishing has been executed."
  ],
  "verification_commands": [
    "gofmt -l .",
    "go test ./...",
    "go test -race ./...",
    "go vet ./...",
    "govulncheck ./...",
    "go build ./cmd/tool",
    "goreleaser check",
    "goreleaser build --snapshot --clean"
  ],
  "evidence_status": "documentation-reviewed",
  "sources": [
    {
      "url": "https://github.com/spf13/cobra",
      "title": "Cobra",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://github.com/charmbracelet/bubbletea",
      "title": "Bubble Tea",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://pkg.go.dev/flag",
      "title": "Go flag",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://pkg.go.dev/net/http",
      "title": "Go net/http",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://pkg.go.dev/os",
      "title": "Go os configuration primitives",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://pkg.go.dev/log/slog",
      "title": "Go structured logging",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://pkg.go.dev/testing",
      "title": "Go testing",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://go.dev/doc/articles/race_detector",
      "title": "Go data race detector",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://golangci-lint.run/docs/welcome/quick-start/",
      "title": "golangci-lint quick start",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://go.dev/doc/security/vuln/",
      "title": "Go vulnerability management",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://riverqueue.com/docs/transactional-enqueueing",
      "title": "River transactional enqueueing",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://goreleaser.com/getting-started/quick-start/",
      "title": "GoReleaser quick start",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://pkg.go.dev/encoding/json",
      "title": "Go JSON API",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://pkg.go.dev/os/signal",
      "title": "Go signal API",
      "checked_date": "2026-10-10"
    },
    {
      "url": "https://pkg.go.dev/encoding/json/v2",
      "title": "Go JSON v2",
      "checked_date": "2026-10-10"
    }
  ],
  "open_questions": [
    "Which OS/architectures and terminals must be supported?",
    "What stable exit codes, JSON schema, configuration precedence and noninteractive behavior are required?",
    "Which signing, package managers and update mechanism will own distribution?"
  ],
  "title": "Go CLI + TUI",
  "language": "Go",
  "group": "Tools & automation",
  "kind": [
    "cli"
  ],
  "ui": "terminal",
  "host": "binary",
  "summary": "Command-line applications and terminal interfaces distributed as binaries.",
  "shape": "Cobra · Bubble Tea when needed · GoReleaser",
  "tradeoff": "Test every target platform; interactive terminals and redirected output have different needs.",
  "research_file": "go-rust.json",
  "reviewed": "2026-10-10",
  "best_practices": [
    "Keep command parsing separate from domain operations. Test help, exit codes, stdout and stderr.",
    "Respect cancellation, timeouts and non-interactive input; do not require a TUI for scripting.",
    "Skip persistence for stateless tools. Delegate long-lived work to a service with a durable job ID.",
    "Verify release binaries on each supported OS and architecture, including the required runtime dependencies."
  ],
  "research_freshness": {
    "core_guidance_checked_on": "2026-10-13",
    "sources": [
      "https://go.dev/doc/tutorial/create-module",
      "https://github.com/spf13/cobra"
    ],
    "scope": "Core framework roles, current setup/agent documentation and cited-source availability rechecked; not a reimplementation or exhaustive semantic audit of every third-party dependency."
  },
  "guide_url": "/stacks/go-cli/",
  "markdown_url": "/stacks/go-cli/guide.md",
  "json_url": "/stacks/go-cli/record.json",
  "architecture_and_migration": {
    "id": "go-cli",
    "version_scope": "Go 1.27 toolchain documentation, Cobra/pflag current guide, Bubble Tea upstream API and GoReleaser v2 documentation. Pin compatible module/tool versions; Bubble Tea major/module-path changes need explicit review. No release matrix was built.",
    "operating_model": "Recommendation: keep the command tree as an adapter over testable application functions. A noninteractive command is a versioned automation interface; a Bubble Tea view is an optional interactive client of the same functions. The executable owns stream, exit-status, cancellation and configuration contracts.",
    "architecture": [
      "Recommendation: Cobra parses and validates arguments, then RunE calls domain operations that return typed results/errors. Formatters own text versus JSON output; diagnostics and progress go to stderr, leaving stdout usable by scripts.",
      "Recommendation: expose a schema/version field in machine-readable output and configuration. Centralize environment/flag/file precedence and secret redaction; preserve old names through an explicit deprecation period.",
      "Recommendation: use Bubble Tea Model/Update/View and commands for terminal interaction. Keep interactive state separate from persisted application configuration, and disable prompts/spinners for pipes or explicit noninteractive mode.",
      "Recommendation: use the established module workflow and GoReleaser target matrix for binary distribution. Native libraries, signing, notarization and OS behavior require per-target checks even when cross-compilation succeeds."
    ],
    "developer_workflow": [
      "Recommendation: inspect existing flags, help output, scripts and configuration before changing the CLI. A new project can start with go mod init and Cobra CLI generation when desired; generation is optional, not an architecture.",
      "Recommendation: run gofmt, go vet ./... and go test ./...; add subprocess-level contract fixtures that capture stdout, stderr and exit status. Domain unit tests alone miss terminal and shell behavior.",
      "Recommendation: exercise --help, invalid flags, piped input, --output json (if implemented), interrupted work and no-TTY execution. Choose and document application exit codes; Cobra does not define every business error code.",
      "Recommendation: after installing a pinned GoReleaser v2, review .goreleaser.yaml, run goreleaser check and goreleaser release --snapshot --clean to prepare local artifacts. These are review commands, not a published release; verify clean-machine install and upgrade on the supported targets. Current GoReleaser OSS installation docs require Go 1.27 when installing the tool from source; a prebuilt tool or a compatible pinned older tool is a separate choice from the application minimum Go version."
    ],
    "avoid": [
      "Avoid logging or progress bars on machine-readable stdout; one extra line can break the calling script.",
      "Avoid os.Exit inside domain functions or cleanup scopes: os.Exit skips deferred calls. Map errors to a code after cleanup in the entry point.",
      "Avoid requiring a TTY for every command; automation needs explicit inputs and a prompt-free path.",
      "Avoid rewriting configuration in place without a version/backup; users may need to downgrade the executable.",
      "Avoid silently switching encoding/json to Go 1.27 encoding/json/v2 during a rewrite; changed serialization defaults require compatibility fixtures and an explicit protocol decision."
    ],
    "transitions": [
      {
        "capability": "cli",
        "existing_contract": "Capture scripts consuming current flags, positional arguments, stdout/stderr, exit codes and completion output.",
        "coexistence": "Recommendation: retain old subcommands/aliases as thin adapters while introducing an explicit JSON mode. Mark renamed flags deprecated through Cobra instead of silently changing their meaning.",
        "target": "Recommendation: Cobra RunE plus centralized result/error mapping; versioned JSON on stdout and diagnostics on stderr. Freeze documented application codes for success, usage and operational failure.",
        "benefits": [
          {
            "benefit": "A stable CLI protocol permits automation and humans to share one executable.",
            "prerequisites": "Consumer fixtures cover streams/status; formatting and error categories are explicit; deprecation schedule preserves callers.",
            "tradeoffs": "Versioned output requires ongoing compatibility ownership; usage errors and remote failures may need different handling."
          }
        ],
        "checks": [
          "Run old calling scripts against the new binary and compare all three output channels.",
          "Verify invalid flags perform no effects and produce the documented exit code.",
          "Pipe JSON to a parser; help/progress/logging must not contaminate its data."
        ],
        "rollback": "Recommendation: install the preceding binary and continue serving the old protocol. Keep newly introduced machine schemas behind explicit versions so callers can choose a compatible response.",
        "sources": [
          "https://cobra.dev/docs/how-to-guides/working-with-flags/",
          "https://pkg.go.dev/encoding/json#Decoder.DisallowUnknownFields",
          "https://pkg.go.dev/os#Exit"
        ],
        "id": "cli-1"
      },
      {
        "capability": "data",
        "existing_contract": "Inventory config paths, default values, flag/environment precedence, secret fields and old readers.",
        "coexistence": "Recommendation: parse both old and versioned schemas through adapters; display migration diagnostics on stderr and offer an explicit migration command with backup. Keep the old file untouched until conversion passes.",
        "target": "Recommendation: a typed versioned config decoded deliberately, with unknown-field policy and semantic validation. Write a same-directory temporary file, validate it and replace only after success; qualify filesystem/OS behavior and cross-process ownership.",
        "benefits": [
          {
            "benefit": "A versioned configuration contract makes upgrades and later rollback predictable.",
            "prerequisites": "Old fixtures exist; migration preserves semantics and backups; one writer and tested replacement behavior are defined.",
            "tradeoffs": "Strict unknown-field rejection can hinder mixed-version use; atomic replacement does not establish crash durability or coordinate concurrent writers."
          }
        ],
        "checks": [
          "Load representative old config, migrate and compare effective settings.",
          "Reject unknown unsupported schema versions before modifying files.",
          "Interrupt conversion and verify either the original or complete new file remains; test permissions on each target OS."
        ],
        "rollback": "Recommendation: restore the backup and preceding executable together. Preserve old readable configuration throughout the downgrade window; do not roll back after newer-only values without an explicit mapping.",
        "sources": [
          "https://pkg.go.dev/encoding/json#Decoder.DisallowUnknownFields",
          "https://cobra.dev/docs/how-to-guides/working-with-flags/"
        ],
        "id": "data-1"
      },
      {
        "capability": "jobs",
        "existing_contract": "Preserve per-item effects, retry decisions, ordering and interrupt behavior for batch commands; a process-local queue has no restart history.",
        "coexistence": "Recommendation: keep the sequential executor available and compare the new bounded executor on fixture inputs. Route one operation class at a time; reuse stable operation IDs across retries.",
        "target": "Recommendation: signal.NotifyContext plus errgroup limit or a fixed worker pool. Pass context through clients, close resources after workers finish, and persist a checkpoint/receipt when interrupted effects need later recovery.",
        "benefits": [
          {
            "benefit": "Bounded fan-out can overlap independent I/O while maintaining a clear cancellation boundary.",
            "prerequisites": "Concurrency quota and total deadline are set; downstream calls honor cancellation; completed and ambiguous effects can be reconciled.",
            "tradeoffs": "No throughput gain is measured; cancellation cannot undo effects; a retry can duplicate a write without provider or business idempotency."
          }
        ],
        "checks": [
          "Interrupt midway through a batch and verify completed, pending and ambiguous items are reported separately.",
          "Simulate one failed item; verify the selected stop/continue policy and bounded parallelism.",
          "Resume using stable IDs and prove acknowledged effects are not repeated."
        ],
        "rollback": "Recommendation: return to sequential execution using the same checkpoint contract. Reconcile ambiguous outcomes first; restarting from item zero is not a safe general rollback.",
        "sources": [
          "https://pkg.go.dev/golang.org/x/sync/errgroup",
          "https://pkg.go.dev/os/signal#NotifyContext",
          "https://pkg.go.dev/os#Exit"
        ],
        "id": "jobs-1"
      },
      {
        "capability": "operations",
        "existing_contract": "Preserve command name, install path, OS/architecture support, update channel and downgrade compatibility.",
        "coexistence": "Recommendation: produce snapshot artifacts beside the old release and smoke-test them without changing the default download. Review generated package-manager changes and publish channels only after target verification.",
        "target": "Recommendation: pinned GoReleaser v2 matrix with metadata/checksums, OS-specific install tests and an explicit signing path. CGO dependencies and macOS signing/notarization need separate toolchain/credential setup; the documented native package notarization flow is Pro; qualify the chosen binary or package flow separately.",
        "benefits": [
          {
            "benefit": "A repeatable artifact matrix reduces manual release assembly.",
            "prerequisites": "Build inputs/tool versions are pinned; each promised target is installed and exercised; signing credentials and package metadata are owned.",
            "tradeoffs": "Cross-compilation is not execution evidence; CGO can require native toolchains; selected signing/notarization automation may require a paid tier."
          }
        ],
        "checks": [
          "Install on clean Linux, macOS and Windows hosts for every advertised architecture.",
          "Verify version metadata, checksums, permissions and executable path.",
          "Upgrade from the old package and downgrade with preserved config; inspect macOS Gatekeeper behavior for the actual downloaded artifact."
        ],
        "rollback": "Recommendation: repoint the owned download/package channel to the previous verified release and keep its artifacts available. Restore compatible configuration with the binary; do not silently overwrite unrelated install locations.",
        "sources": [
          "https://goreleaser.com/getting-started/how-it-works/",
          "https://goreleaser.com/customization/builds/go/",
          "https://goreleaser.com/customization/sign/notarize/",
          "https://goreleaser.com/customization/publish/snapshots/"
        ],
        "id": "operations-1"
      }
    ],
    "sources": [
      {
        "url": "https://cobra.dev/docs/how-to-guides/working-with-flags/",
        "title": "Cobra flag guide",
        "claim": "Flag scoping, validation, deprecation and optional configuration integration are explicit."
      },
      {
        "url": "https://github.com/charmbracelet/bubbletea",
        "title": "Bubble Tea upstream",
        "claim": "The TUI uses Model/Update/View with commands for effects."
      },
      {
        "url": "https://pkg.go.dev/encoding/json#Decoder.DisallowUnknownFields",
        "title": "Go JSON decoder",
        "claim": "Typed decoding and DisallowUnknownFields are available; schema policy is the application responsibility."
      },
      {
        "url": "https://pkg.go.dev/os#Exit",
        "title": "os.Exit",
        "claim": "Process exit skips deferred calls; exit-code meanings need an application contract."
      },
      {
        "url": "https://pkg.go.dev/golang.org/x/sync/errgroup",
        "title": "errgroup",
        "claim": "Group limit and cancellation support bounded batch execution."
      },
      {
        "url": "https://pkg.go.dev/os/signal#NotifyContext",
        "title": "os/signal",
        "claim": "NotifyContext exposes signal cancellation."
      },
      {
        "url": "https://goreleaser.com/getting-started/how-it-works/",
        "title": "GoReleaser workflow",
        "claim": "Release configuration and build/package/publish workflow are described; snapshot behavior has its own source."
      },
      {
        "url": "https://goreleaser.com/customization/builds/go/",
        "title": "GoReleaser Go builds",
        "claim": "GOOS/GOARCH matrix and environment/CGO settings are configurable."
      },
      {
        "url": "https://goreleaser.com/customization/sign/notarize/",
        "title": "GoReleaser notarization",
        "claim": "Signing/notarization requires Apple credentials; the native package flow is Pro and uses Apple tools. Cross-platform binary notarization is a separate documented flow."
      },
      {
        "url": "https://goreleaser.com/customization/publish/snapshots/",
        "title": "GoReleaser snapshots",
        "claim": "Snapshot mode builds review artifacts without publishing to a release channel."
      },
      {
        "url": "https://goreleaser.com/getting-started/quick-start/",
        "title": "GoReleaser quick start",
        "claim": "goreleaser check validates config; release --snapshot --clean builds local review artifacts."
      },
      {
        "url": "https://goreleaser.com/getting-started/install/oss/",
        "title": "GoReleaser OSS installation",
        "claim": "Current source installation requires Go 1.27; verified prebuilt binaries are another documented installation method."
      },
      {
        "url": "https://go.dev/doc/go1.27",
        "title": "Go 1.27 release notes",
        "claim": "Introduces encoding/json/v2 with changed defaults; serializer replacement requires compatibility review."
      }
    ],
    "reviewed_at": "2026-10-11",
    "evidence": "documentation-reviewed"
  },
  "rewrite_url": "/rewrite/guide.md",
  "migration_contracts_url": "/rewrite/contracts.json",
  "agent_workflow": [
    "Read README, dependency manifests, lockfiles, runtime pins and the maintained project workflow before changing anything. Preserve an existing stack unless reconsidering it is part of the request.",
    "Use this guide to select tools by requirement. Resolve compatible versions from official and installed-version documentation; record the actual lockfile and runtime versions.",
    "Create a plan for schema changes, identity, authorization, external effects and deployment. A library choice does not complete its integration.",
    "Run relevant checks after configuration. Exercise the real interface, failure paths and packaged artifact on the intended target. Report commands, versions, results and untested behavior.",
    "On failure, retain the command and diagnostic, fix the failing prerequisite and resume there. Do not regenerate over existing work or suppress failures to make a check green."
  ],
  "selection": {
    "native_ui": false,
    "static_hosting": false,
    "offline_client_candidate": false
  },
  "coverage_note": "Tools are curated starting points for this application role. Exact versions, integrations and offline behavior require project-specific qualification."
}
