Command history

One of cy's distinguishing features is that it can detect the commands that you run. It also records:

  • When the command was executed
  • When it finished executing
  • All of the output the command produced (by indexing into .borg files)
  • The directory in which the command was run

This metadata is stored in an SQLite database called cmd.db (in your :data-directory) and accessible in Janet via the cmd/query API.

cy uses this information to provide a range of functionality:

Installation

To enable command detection, you must configure your shell to emit OSC 133 escape sequences that mark the prompt and command boundaries. Many prompt frameworks (like Starship, oh-my-posh, and Powerlevel10k) emit OSC 133 sequences automatically. If you use one of these, command detection should work without additional configuration.

For manual configuration:

bash

After installing and sourcing bash-preexec, you can use this script to get Bash to emit the correct sequences.

zsh

For zsh, you only need to source this script.

fish

As of 4.0.0, fish reports OSC133 sequences automatically.

Directory detection

By default, cy detects the directory in which a command is executed by regularly getting the working directory of the process running in your terminal (such as a shell.) This produces incorrect results in cases like ssh, where the actual directory is distinct from the one reported by examining the process.

To address this, cy supports the OSC-7 quasi-standard. OSC-7 is a custom escape sequence that allows a program to indicate its current directory to the terminal emulator.

You must explicitly configure your shell (or any other program) to emit OSC-7 sequences. You can find instructions for doing so here. cy does not do any special processing of the string you emit using OSC-7: it need not be a valid directory.

How does it work?

A terminal multiplexer is like a proxy: it is an intermediary between your actual terminal and one or more virtual terminals that it controls. It also responsible for passing the output a program (such as a shell) produces to its corresponding terminal. This control means that your terminal multiplexer can do whatever calculations it wants on that output, including (in cy's case) recording it.

cy uses this ability to observe the state of the terminal before and after interpreting the output of the underlying process (otherwise known as a write made to standard output or error).

A terminal emulator is just a state machine that interprets a stream of bytes and adjusts the state of the screen accordingly. The screen is a grid of cells, each of which contains a Unicode character and has other styling information.

When your shell emits OSC 133 sequences, cy receives explicit markers for:

  • Prompt start: The shell is about to display a prompt
  • Command start: The user has started typing a command
  • Command executed: The command is being executed
  • Command finished: The command has finished, along with its exit code

By correlating these markers with actual screen cells, cy can categorize each cell.

This approach has downsides. One is that cy is unable to distinguish between the output produced when running multiple processes at once, such as with Bash's backgrounding functionality (i.e. &.)