desertbit
grumble
Go

A powerful modern CLI and SHELL

Last updated Jun 26, 2026
551
Stars
59
Forks
15
Issues
0
Stars/day
Attention Score
58
Language breakdown
Go 99.6%
Dockerfile 0.4%
Files click to expand
README

Grumble - A powerful modern CLI and SHELL

GoDoc Go Report Card

There are a handful of powerful go CLI libraries available (spf13/cobra, urfave/cli). However sometimes an integrated shell interface is a great and useful extension for the actual application. This library offers a simple API to create powerful CLI applications and automatically starts an integrated interactive shell, if the application is started without any command arguments.

Hint: We do not guarantee 100% backwards compatiblity between minor versions (1.x). However, the API is mostly stable and should not change much.

asciicast

Introduction

Create a grumble APP.

var app = grumble.New(&grumble.Config{
	Name:        "app",
	Description: "short app description",

Flags: func(f *grumble.Flags) { f.String("d", "directory", "DEFAULT", "set an alternative directory path") f.Bool("v", "verbose", false, "enable verbose mode") }, })

Register a top-level command. Note: Sub commands are also supported...

app.AddCommand(&grumble.Command{
    Name:      "daemon",
    Help:      "run the daemon",
    Aliases:   []string{"run"},

Flags: func(f *grumble.Flags) { f.Duration("t", "timeout", time.Second, "timeout duration") },

Args: func(a *grumble.Args) { a.String("service", "which service to start", grumble.Default("server")) },

Run: func(c *grumble.Context) error { // Parent Flags. c.App.Println("directory:", c.Flags.String("directory")) c.App.Println("verbose:", c.Flags.Bool("verbose")) // Flags. c.App.Println("timeout:", c.Flags.Duration("timeout")) // Args. c.App.Println("service:", c.Args.String("service")) return nil }, })

Run the application.

err := app.Run()

Or use the builtin grumble.Main function to handle errors automatically.

func main() {
	grumble.Main(app)
}

Shell Multiline Input

Builtin support for multiple lines.

>>> This is \
... a multi line \
... command

Flags

You can pass flags in two ways: cmd --flag value or cmd --flag=value There are some exceptions/additions to this:

  • bool: cmd --boolflag offer a third option that does not require a value
  • string: cmd --stringflag="some test string" leads to value some test string, as double quotes are stripped from the value

Separate flags and args specifically

If you need to pass a flag-like value as positional argument, you can do so by using a double dash: >>> command --flag1=something -- --myPositionalArg

Remote shell access with readline

By calling RunWithReadline() rather than Run() you can pass instance of readline.Instance. One of interesting usages is having a possibility of remote access to your shell:
handleFunc := func(rl *readline.Instance) {

var app = grumble.New(&grumble.Config{ // override default interrupt handler to avoid remote shutdown InterruptHandler: func(a *grumble.App, count int) { // do nothing }, // your usual grumble configuration }) // add commands app.RunWithReadline(rl)

}

cfg := &readline.Config{} readline.ListenRemote("tcp", ":5555", cfg, handleFunc)

In the client code just use readline built in DialRemote function:

if err := readline.DialRemote("tcp", ":5555"); err != nil {
    fmt.Errorf("An error occurred: %s \n", err.Error())
}

Samples

Check out the sample directory for some detailed examples.

Projects using Grumble

  • grml - A simple build automation tool written in Go: https://github.com/desertbit/grml
  • orbit - A RPC-like networking backend written in Go: https://github.com/desertbit/orbit

Known issues

  • Windows unicode not fully supported (issue)

Additional Useful Packages

  • https://github.com/AlecAivazis/survey
  • https://github.com/tj/go-spin

Credits

This project is based on ideas from the great ishell library.

License

MIT

🔗 More in this category

© 2026 GitRepoTrend · desertbit/grumble · Updated daily from GitHub