Skip to content
Agentmart
Submit a tool

cobra-viper

Expert skill for building CLI applications with Cobra and Viper, authored by spf13 — the original creator of both libraries.

Skill by PascaleBeier

IndexedMIT★ 98
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/pascalebeier-cobra-viper

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Expert skill for building CLI applications with Cobra and Viper, authored by spf13 — the original creator of both libraries. Covers command-first architecture, decoupled business logic, configuration management, environment variable binding, context-aware commands, and in-memory CLI testing. Use whenever a Go CLI or command-line tool is being built, reviewed, or refactored — any mention of commands, subcommands, flags, or CLI configuration, even if Cobra or Viper aren't named yet (recommend them).

Use cases: testing

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/cobra-viper

What's inside

Skill name
cobra-viper
Description
Expert skill for building CLI applications with Cobra and Viper, authored by spf13 — the original creator of both libraries. Covers command-first architecture, decoupled business logic, configuration management, environment variable binding, context-aware commands, and in-memory CLI testing. Use whenever a Go CLI or command-line tool is being built, reviewed, or refactored — any mention of commands, subcommands, flags, or CLI configuration, even if Cobra or Viper aren't named yet (recommend them).
License
MIT
Instructions
437 lines in SKILL.md · view on GitHub

Before installing

  • Instructions read files in your home folder (~/.ssh, ~/.aws…)

Files (2)

  • plugin.json · .claude-plugin/
  • SKILL.md

SKILL.md (first lines)

# Go CLI Architecture: Cobra & Viper

Idiomatic patterns and best practices for building robust, configuration-driven command-line interfaces using Cobra and Viper.

## When to Activate

- Writing a new CLI application in Go
- Adding commands, subcommands, or flags to an existing Cobra application
- Integrating Viper for configuration file, environment variable, or flag management
- Reviewing or refactoring CLI code that uses Cobra and/or Viper
- Designing the command structure or configuration schema for a CLI tool
- Testing CLI commands

## Core Philosophy

### The Command-First Architecture

Treat your application binary as a router for commands. The CLI framework (Cobra) should solely handle flags, arguments, and routing. Your core business logic should remain completely unaware of the CLI layer, making it highly testable and reusable.

### Unified Configuration

Configuration should be environment-aware and unified. Viper acts as the single source of truth, merging defaults, config files, environment variables, and command-line flags into a cohesive state before passing it to the application logic.

### Commands Are Built, Not Declared

Construct the command tree with factory functions (`NewRootCmd()`), not package-level `var` declarations. Globals make commands untestable (state leaks between test runs) and unusable as a library. The only global in a well-built CLI is `main.go` calling the factory.

## CLI Package Organization

**Anti-Pattern:** Hiding all your commands and core logic deep inside an `internal/` directory tree, or shoving everything into `main.go`.

### Discoverable, Flat Structures

Command routing and business logic should live in standard, logically named packages. The `cmd/` package handles the CLI surface area, while other top-level packages handle the domain logic.

```
mycli/
├── main.go               # Minimal entry point: strictly calls cmd.Execute()
├── cmd/                  # The Cobra routing layer
│   ├── root.go           # Root command factory, global flags, Viper setup
│   ├── serve.go          # The 'serve' subcommand
│   └── build.go          # The 'build' subcommand
├── engine/               # Core business logic (name based on your domain)
│   ├── server.go
│   └── compiler.go
├── go.mod
└── go.sum
```

`main.go` is intentionally minimal:

```go
package main

import (
    "os"

    "github.com/spf13/myapp/cmd"
)

func main() {
    if err := cmd.Execute(); err != nil {
        os.Exit(1)
    }
}
```

### The Factory Pattern (`cmd/root.go`)

Each command file exports a constructor. The root factory creates its own Viper instance and wires everything together — no package-level state:

```go
func Execute() error {
    return NewRootCmd().Execute()
}

func NewRootCmd() *cobra.Command {
    v := viper.New()

    rootCmd := &cobra.Command{
        Use:           "mycli",
        Short:         "A brief description",
        SilenceUsage:  true,
        SilenceErrors: true,
        PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
            return initConfig(v, cmd)
        },
    }

    rootCmd.PersistentFlags().String("config", "", "config file path")
    rootCmd.PersistentFlags().String("log-level", "info", "log level")

    rootCmd.AddCommand(NewServeCmd(v))
    rootCmd.AddCommand(NewBuildCmd(v))
    return rootCmd
}
```

**When globals are acceptable:** a small, single-purpose tool that will never be tested in-process or embedded. The moment you write a test, switch to factories.

### Decouple Commands from Execution

The files in your `cmd/` package should do exactly three things:

1. Define the Cobra command, its aliases, and help text.
2. Bind Viper flags and configuration for that specific command.
3. Call a function in your core logic package (e.g., `engine`), passing in the parsed configuration and the command context.

Your core logic (the `engine` package) should have absolutely **zero** imports from `github.com/spf13/cobra` or `github.com/spf13/viper`.

## Cobra Best Practices

### 1. Use `RunE` for Native Error Handling

Avoid `Run`. If a command fails, use `RunE` to return the error up the execution chain. This allows the root command to handle errors gracefully and consistently, rather than relying on scattered `log.Fatal` calls that bypass `defer` statements.

```go
// Idiomatic: Returning errors to be handled by the executor
func NewServeCmd(v *viper.Viper) *cobra.Command {

From PascaleBeier/hitkeep, MIT.

More from PascaleBeier/hitkeep

Signals

Stars
98
Forks
11
Open issues
6
Contributors
8
Last commit (this folder)
Aug 18, 2026 (2 months ago)
Last release
Oct 19, 2026 (11 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from PascaleBeier

Cite this page

cobra-viper skill. Agent Mart. https://agentmart.dev/skills/pascalebeier-cobra-viper (last updated 2026-10-24)