# cod: a completion daemon that learns from --help output

> cod is a Go completion daemon for bash, fish and zsh that notices when you run a command with --help, asks whether it may learn it, then parses the help text and generates shell completions from it. It stores what it learns in a SQLite database under your XDG data directory, and its release history is thin, with v0.1.0 from 2021 as the most recent tagged version.

**dim-an/cod** — cod is a completion daemon for bash/fish/zsh

- Repository: https://github.com/dim-an/cod
- Stars: 556 · Forks: 24
- Language: Go
- License: Apache-2.0
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/dim-an-cod

## What cod does and the idea behind it

cod is a completion daemon for bash, fish and zsh. It detects usage of --help commands, parses their output, and generates auto-completions for your shell.

The idea is that the help output of a command already contains the flags, and re-typing it into a completion specification is busy work that goes stale. cod takes the help text as the specification.

The overview describes the loop. Cod checks each command you run in the shell, and when it detects usage of the --help flag it asks if you want it to learn this command. If you choose to allow cod to learn the command, cod runs the command itself, parses the output, and generates completions based on the --help output.

The prompt is the interesting part, because it is not a silent background scan. You run a command with --help, you get asked, and you say yes. That is a deliberate safety property for a tool that executes commands on your behalf, since the set of binaries it will run is the set you approved.

The repository layout shows the shape of it. There is daemon.go for the daemon, application.go and commands.go for the command line, api_attach.go, ui.go, main.go, a cod.plugin.zsh file for the zsh plugin, and directories for the datastore, misc, parse_doc, server, shells, test and util. The parse_doc/ directory is where the help output parsers live.

The audience is a command line user who is willing to add two lines to their shell init and let a daemon learn the tools they actually use.

## How cod decides a command is a help invocation

Before cod will run a command, it applies three checks to decide whether the command is a help invocation.

The first is that it checks if the --help flag is used. The second is that it checks that the command is simple, meaning it does not contain any pipes, file descriptor redirections, and other shell magic. The third is that it checks that the command exit code is 0.

Those three checks together are the safety model, and each one closes a hole. Without the first, cod would run any command it saw. Without the second, a command with a pipe or a redirect could do something entirely different from what the help text describes. Without the third, a command that failed might have produced an error message that the parser would misread as a flag list.

The exit code check has an interesting consequence. A tool whose --help exits non-zero, which some tools do, will not be learned automatically.

There is also a manual escape hatch. If cod cannot automatically detect that your command is a help invocation, you can use the learn subcommand to learn the command anyway.

That subcommand is the answer to the case the checks reject, and the three checks together explain why the daemon only ever runs simple, successful, --help invocations of binaries you approved.

## How cod runs the command and what it stores

The documentation is precise about how the command is executed, and the details matter if you are security minded about it.

Cod always uses absolute paths to run programs, so it finds the binary in $PATH or resolves a relative path if required. Arguments other than the binary path are left unchanged, and the current shell environment and current working directory will be used.

If the program is successfully executed, cod stores the absolute path to the binary, any used arguments, the working directory, and environment variables. That stored information is what lets cod update the command later if required, and the documentation points at cod help update for that.

Storing the environment variables is the part that deserves attention. It is what makes the update possible, because a command whose behaviour depends on a variable will need that variable set the same way later, and it also means the daemon's data store holds a copy of the environment your shell was in.

The second parser is tuned for a specific case. The generic parser works with most help pages and recognizes flags, starting with -, while not recognizing subcommands. There is also a special parser tuned for the python argparse library that recognizes flags and subcommands.

So a Python tool built with argparse gets better completions than a generic tool, and anything with a subcommand structure on a non-argparse help page gets flags but not subcommands. That is the practical ceiling of the approach, and it is worth knowing before you wonder why a completion set is thin.

## Installing the binary and wiring it into each shell

You can either download the cod binary or build it for your OS and put it into your $PATH, and after that you need to edit your init script to add a few lines for the daemon to work correctly.

For bash, the line goes into your ~/.bashrc:

```bash
   source <(cod init $$ bash)
```

For zsh it goes into your ~/.zshrc:

```bash
   source <(cod init $$ zsh)
```

For fish it goes into your ~/.config/fish/config.fish, and the syntax is different because fish pipelines work differently:

```bash
   cod init $fish_pid fish | source
```

There is also a zinit plugin manager form for zsh:

```bash
   zinit wait lucid for \
     dim-an/cod
```

And an alternative installation through Fig, which is described as installing cod in bash, zsh or fish with just one click.

The $$ and $fish_pid arguments are the shell process identifiers, which is how the init line tells the daemon which shell session to attach to.

If you build from source, the documentation recommends having at least Go v1.19 installed:

```bash
  git clone https://github.com/dim-an/cod.git
  cd cod
  go build
```

and the alternative is go get -u github.com/dim-an/cod.

## The zsh completion prerequisite that catches people out

For zsh there is a prerequisite that the documentation puts first, and it is a common failure.

cod requires an initialized completion system. In many cases it is already the case, for example if you are using oh-my-zsh or a similar framework, and you can check whether your completion system is already initialised by using the type compdef command:

```bash
  # Completion system IS initialized
  $ type compdef
  compdef is a shell function from /usr/share/zsh/functions/Completion/compinit

  # Completion system IS NOT initialized
  $ type compdef
  compdef not found
```

If you find that you need to initialize the completion system, you can do it by calling the compinit function in your .zshrc before initializing cod itself, or by executing the compinstall command from your shell, which will modify your .zshrc file for you. The documentation also links the zsh documentation on the completion system.

The order matters here, and it is the kind of thing that produces a silent failure. A zsh session where compdef is not defined cannot load cod's completions, and the symptom is that nothing happens rather than an error message.

The bash and fish paths do not have this requirement, which is why the documentation raises it only for zsh.

## Configuration, the trust rules and the data directories

cod reads its configuration from the default config file at $XDG_CONFIG_HOME/cod/config.toml, and the file lets you specify rules to either ignore or trust specified binaries.

That is the security-relevant knob. Because cod executes the binaries it learns, the trust list is how you say which programs may be run automatically, and the ignore list is how you say which may not. The documentation does not enumerate the file format, so the way to learn it is to print an example:

`cod example-config`

and to write one to the default directory of the config file, which is $XDG_CONFIG_HOME/cod/config.toml, with:

`cod example-config --create`

The generated data lives separately. cod uses $XDG_DATA_HOME/cod, defaulting to ~/.local/share/cod, to store all generated data files. So the configuration, which is yours, and the learned completions, which are generated, sit in two different XDG locations.

The dependency list explains the storage choice. The module requires github.com/ncruces/go-sqlite3, so the learned completions are kept in a SQLite database, along with alecthomas/kingpin for the command line, pelletier/go-toml for the configuration parsing, golang.org/x/crypto, and stretchr/testify for the tests. The Makefile shows the same shape, with a build target that stamps the git SHA into the binary, a test target that runs the suite against the built binary, and an install target that calls a Python release script.

## Where cod is the wrong choice

The first limit is macOS with the default bash. The documentation says the default bash that is bundled with macOS is too old and cod doesn't support it, while zsh is known to work with the latest version on macOS and Linux, tested with v5.5.1 and 5.7.1. So a macOS user on bash is out of luck unless they install a newer bash, and that is a fairly common configuration for people who work in both shells.

The second is subcommand completion. The generic parser recognizes flags but not subcommands, and only the argparse-specific parser handles subcommands. A tool with a deep subcommand tree and a non-argparse help page will get partial completions, which is a disappointing result that looks like a bug in the tool.

The third is the release history. The tags are v0.0.0 from 2020-02-01 and v0.1.0 from 2021-05-12, and the last push was on 2026-09-03. There is work in the tree, since there is a server/ directory, a datastore/ directory and an AGENTS.md, but the tagged version is years old, so an install from the releases page and a build from master are different things, and the documentation is thin about which is which.

The fourth is the trust model. cod runs binaries on your machine and stores the environment it found them in. That is a meaningful capability for a tool that starts with your shell configuration, and the mitigation is the trust and ignore list, which you have to learn about and configure yourself.

Compare that with a completion generator that reads a spec file instead of executing anything. The difference in approach is that a spec-driven generator gives you exactly the completions the author wrote down, with no execution and no trust decision, while cod derives them from the real help output and therefore needs permission to run things. If you want completions for a fixed set of tools, the spec route is less machinery, and if you want whatever the tool actually supports, cod gives you that at the cost of a daemon that executes programs.

## Licence, supported shells and what to check first

cod is released under the Apache-2.0 licence, with the text in the LICENSE file at the repository root,. The Apache 2.0 terms are permissive and include a patent grant, which is a reasonable fit for a tool you are likely to run as a background daemon, and you should read the LICENSE file yourself for the exact wording.

The supported shells and operating systems are stated in the documentation, with the tested versions given, and that list is the practical acceptance criteria.

For zsh, cod is known to work with the latest version, tested with v5.5.1 and 5.7.1, on macOS and Linux. For bash it works with the latest version, tested with 4.4.20 and v5.0.11, on Linux, and the default bash bundled with macOS is too old and unsupported. For fish it works with the latest version, tested with v3.1.2, on Linux, and the author notes they did not have a chance to test it on macOS.

The last push was on 2026-09-03, and the repository is not archived, so the tree is about seven weeks old relative to today.

What to check before you rely on it is a short list. Run the init command for your shell by hand and see what it emits before you put it in your init file, because the init line is process substitution and you want to know what it is doing before it runs on every new shell. On zsh, confirm that type compdef finds something, because that check is the difference between working and silently not working.

Then generate an example config and read it, so you know which binaries you are trusting before the daemon starts running them. And keep the learn subcommand in mind for the tools the three automatic checks reject, since that is the documented path for a command that does not fit the pattern.

## Conclusion

cod fits a user who runs a lot of command line tools with rich help output and wants completions for them without hand writing a spec for each, and it is a good fit for a machine where you control the shell setup. It does not fit a macOS user with the bundled bash, which the documentation says is too old and unsupported, and it does not fit a workflow that needs subcommand level completion, because the generic parser does not recognise subcommands. Before you adopt it, run cod init for your shell and check that your shell's completion system is initialised, read the config example so you know which binaries you trust or ignore, and confirm the release you install matches the shell you run.

## FAQ

### What is cod and how does it generate shell completions?

cod is a completion daemon for bash, fish and zsh. It checks each command you run, and when it detects usage of the --help flag it asks if you want it to learn that command, then runs the command itself, parses the output and generates completions based on the --help output.

### How do I install cod and set it up in my shell?

Download the binary or build it for your OS and put it into your $PATH, then add a line to your init script: source <(cod init $$ bash) in ~/.bashrc, source <(cod init $$ zsh) in ~/.zshrc, or cod init $fish_pid fish | source in ~/.config/fish/config.fish.

### Why does cod not work in my zsh?

cod requires an initialized zsh completion system. Check it with the type compdef command, and if it is not initialized, call the compinit function in your .zshrc before initializing cod, or run the compinstall command which modifies your .zshrc for you.

### What does cod store, and where?

When a program runs successfully, cod stores the absolute path to the binary, any used arguments, the working directory and the environment variables, so the command can be updated later with cod help update. Generated data files go to $XDG_DATA_HOME/cod, defaulting to ~/.local/share/cod, and the configuration file is $XDG_CONFIG_HOME/cod/config.toml.

### Does cod work with the bash bundled with macOS?

No. The documentation states that the default bash that is bundled with macOS is too old and cod doesn't support it. zsh is known to work on macOS and Linux, bash works on Linux, and fish was tested on Linux with the author noting they did not have a chance to test it on macOS.

### What licence does cod use?

cod is released under the Apache-2.0 licence, with the terms in the LICENSE file at the repository root. The only tagged releases are v0.0.0 from 2020-02-01 and v0.1.0 from 2021-05-12, and the last push to the repository was on 2026-09-03.

## Sources

- [dim-an/cod on GitHub](https://github.com/dim-an/cod)
- [Issues](https://github.com/dim-an/cod/issues)
- [License: Apache-2.0](https://github.com/dim-an/cod/blob/master/LICENSE)
- [README](https://github.com/dim-an/cod/blob/master/README.md)
- [Releases](https://github.com/dim-an/cod/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/dim-an-cod
