transcript is a CLI tool for snapshot testing other CLI tools.

TODO: Video here.


Automatically record a shell session or type-out a transcript file by hand,
then use the check command!

cat > demo.cmdt <<EOF
$ echo stdout
1 stdout

$ echo stderr 1>&2
2 stderr

# Non-zero exit codes.
$ false
? 1

transcript check ./demo.cmdt


go get -u

NOTE: Transcript is not Go-specific. It is simply written in Go and Go provides
a convenient distribution mechanism. If there is expressed interest, it may be
re-packaged for various additional distribution channels.


Initial authoring of tests is performed in an interactive shell.

To record an interactive session to a file, run:

transcript shell -o example.cmdt

The interactive shell supports standard readline behaviors and can be exited
with ^d or exit like most other shells.


To interpret a transcript file and validate that the results (stdio output and
exit codes) have not changed, run the following:

transcript check example.cmdt

Check returns a non-zero exit code if any check failures or other errors occur.


When the CLI tools under test are modified, the quickest way to update test
files is to use the automated update process:

transcript update example.cmdt

This will interpret a command transcript file, but does not check any output or
exit status expectations. Instead, the given file will be rewritten with the
newly observed results.


While transcript files can be edited by hand, more advanced edits can be made
using an interactive update session. The experience should be familiar to users
of git rebase --interactive.

NOTE: Not yet implemented.

“Command Transcript” File Format

Transcript files represent recorded shell sessions.

.cmdt is the recommended file extension.

This format is intended to be human-editable, but sacrifices some ease of
hand-authoring in exchange for added functionality. Users are expected to
primarily use the transcript tool to create and update transcripts.


Cmdt files are line-oriented. Each line represents an instruction to the
Transcript interpreter. Each instruction begins with an opcode, followed by a
space. The remainder of an instruction line forms arguments to the operation
specified by the opcode.


Operations with the following opcodes are supported:

# — comment

Comments may appear anywhere in a .cmdt file and are ignored
by the interpreter.

A space is not required after the # opcode.

Blank lines are also treated as comments.

$ — command

Run a shell command.

Supports the subset of Bash syntax provided by

1, 2 — output

Match a line of output from a particular stdio stream of the previously
run command.

The opcodes are named after the file descriptors of stdout
(1) and stderr (2) respectively.

Output lines are matched exactly. More flexible matching may be
configured by % directives in a future version of

Transcript checking assumes that the interleaving of stdout and stderr
lines is significant and that output lines are written atomically.
The ordering of concurrent writes to both streams is undefined, which
will lead to flakey tests. Incrementally written lines will be buffered,
which may mask text interleaving issues that would affect users. Both of
these shortcomings may be mitigated in the future.

? — exit-code

Exit code of the previously run command.

If omitted, the exit code defaults to 0.

% — directive

Reserved for future use by Transcript.


In addition to the transcript CLI, there is a Go API for users who wish to
embed cmdt scripts in to their existing Go test suites.

import (
  _ "embed"


//go:embed test.cmdt
var fs embed.FS

func TestCLI(t *testing.T) {
  f, _ := fs.Open("test.cmdt")
  defer f.Close()

NOTE: Assuming that ./test.cmdt uses the CLI tool you are developing, you
must first build your tool and ensure it is on PATH.

There is also a CheckString function for small, inline tests. However, prefer
to use .cmdt files so that the transcript tool can assist with updates and


View Github