Command Line¶
RUNBOOK is one of three things: a runbook directory (it must contain
runbook.md), a single all-in-one markdown file whose ## headings are the
steps (see Single-file runbooks),
or a directory holding several of either, in folders nested to any depth
(see Choosing a runbook). Given such a
directory of runbooks, the page opens on a folder tree and the operator picks
one; runsheets examples shows the five bundled example runbooks that way. It is
the only positional argument. Leave it out and the bundled examples/directory_based_runbooks/hello
is served, which is the quickest way to see the tool;
--init is the one mode that always needs a path. dir: in the config file
or RUNSHEETS_DIR can supply it instead; see Settings.
Options¶
| Option | Default | Meaning |
|---|---|---|
-c, --config FILE |
./config/runsheets.yml |
Config file to read in place of the project config; see Settings. A file named here must exist. |
-p, --port PORT |
4567 |
Port to listen on, from 1 to 65535. |
-b, --bind HOST |
127.0.0.1 |
Address to bind to. See the note below before changing it. |
--runs-dir DIR |
~/.local/share/runsheets/runs |
Where session records, logs and run records are written. |
-o, --open |
off | Open the default browser once the server is listening. --no-open turns it off. |
--check |
off | Load the runbook, print authoring warnings, and exit without serving. On a directory of runbooks, every runbook is checked, one line each. See Checking runbooks. --no-check turns it off. |
--init |
off | Create a starter runbook at RUNBOOK and exit: a directory with runbook.md, two steps, verify.md and rollback.md, or a single file when the path ends in .md. Refuses to touch an existing file or a non-empty directory. --no-init turns it off. |
--dump |
off | Print the settings in force as a config file to stdout and exit. --no-dump turns it off. See Saving settings. |
-e, --engineer NAME |
ask | Who is starting the session. Without it the start page asks, pre-filled from git config user.name, else $USER. See The session. |
-w, --why TEXT |
ask | Why the session is being started: its first note. With --engineer too, the session starts at once and the start page is skipped. |
--log-level LEVEL |
info |
The session log's level: debug, info, warn, error or fatal, in any case. See The session log. |
--verbose |
The same as --log-level debug. |
|
-q, --quiet |
off | Do not echo the session log to the terminal. --no-quiet turns it off. |
-v, --version |
Print the version and exit. | |
-h, --help |
Print usage and exit. |
Examples¶
Start a new runbook, then serve it:
runsheets --init ops/runbooks/db-refresh # a directory
runsheets --init ops/runbooks/db-refresh.md # or a single file
runsheets --open ops/runbooks/db-refresh
Serve a runbook and open it, as a directory or as one all-in-one file:
runsheets --open ops/runbooks/staging-teardown # a directory
runsheets --open ops/runbooks/db-maintenance.md # a single file
runsheets --open ops/runbooks # choose among them
Serve on another port because something else has 4567:
Start the session from the command line, skipping the start page:
Keep run records inside a project (but outside the runbook):
Validate every runbook in a repository (a directory of runbooks is checked as a whole):
Checking runbooks¶
--check loads the runbook, prints its authoring warnings to stderr
prefixed runsheets: warning:, and prints one line to stdout:
On a directory of runbooks every runbook gets that line with its slug in brackets, and each warning is prefixed with the slug:
runsheets: warning: platform/deploy: 020-roll-out: automated step has no executable block
Deploy [platform/deploy]: 4 steps, 1 warnings
Backup [platform/database/backup]: 3 steps, 0 warnings
A runbook in the directory that cannot be read (an unreadable file, front matter that is not valid YAML, a clash of names) is never dropped from the check. It is reported as an error with its slug and no summary line:
The exit status is 1 if any runbook warned or could not be read, else
0.
What it prints¶
runsheets 0.0.1
Runbook: Staging Infrastructure Teardown and Rebuild (/Users/you/ops/runbooks/staging-teardown)
Runs: /Users/you/.local/share/runsheets/runs
Config: /Users/you/.config/runsheets/runsheets.yml
Session: starts in the browser (who and why)
Open http://127.0.0.1:4567/?token=3f9c0d6e8a1b4c2f9e7d5a3b1c0f8e6d in your browser
Press Ctrl-C to end the session and stop
The link carries this start's session key. Opening it gives the browser
the key as a cookie and drops it from the address bar; every request
needs the key, so another account on the machine that can reach the port
still sees nothing. --open opens this link. Each start makes a new key,
so a tab or bookmark from an earlier start shows "Open the link from the
terminal" until the new link is opened. With an IPv6 --bind the address
is bracketed, http://[::1]:4567/?token=….
Started on a directory of runbooks, the second line is Library: with the
number of runbooks and folders. When --engineer and --why are both set
the session has already started, and the Session: line gives its id and
the path of its log:
Session: 20261010T141502, log /Users/you/.local/share/runsheets/runs/sessions/20261010T141502/session.log
Served on one runbook, its authoring warnings are printed to stderr
before the banner, prefixed runsheets: warning:. The server still
starts; warnings mark blocks and steps in the page but do not block
serving. In a library, each runbook's warnings are on its pages and in
--check.
Puma then prints its own startup lines. From then on, unless --quiet is
given, the session log is echoed to the terminal as it is written. Press
Ctrl+C to end the session and stop; see Stopping.
Exit status¶
| Status | When |
|---|---|
0 |
Normal exit, or --check found no warnings. |
1 |
Bad arguments or settings, the runbook could not be loaded, the port is in use, or --check found warnings or a runbook it could not read. |
Settings¶
Every option is a setting with the same name (port, bind, runs_dir,
open, check, init, dump, engineer, why, log_level, quiet),
and the RUNBOOK argument is the setting dir. --verbose sets
log_level to debug.
Settings are layered with myway_config;
each layer overrides the one below it, and anything a layer leaves out
comes from further down:
- Command line. Whatever is given wins outright.
- Environment variables,
RUNSHEETS_plus the setting name in upper case:RUNSHEETS_PORT,RUNSHEETS_BIND,RUNSHEETS_RUNS_DIR,RUNSHEETS_OPEN,RUNSHEETS_CHECK,RUNSHEETS_INIT,RUNSHEETS_DUMP,RUNSHEETS_DIR,RUNSHEETS_ENGINEER,RUNSHEETS_WHY,RUNSHEETS_LOG_LEVEL,RUNSHEETS_QUIET. - The project config,
./config/runsheets.ymlin the current directory, or the file--config FILEorRUNSHEETS_CONFIGnames in its place. The project file may be absent; a file named explicitly must exist. - The user config,
~/.config/runsheets/runsheets.yml(or under$XDG_CONFIG_HOME), which myway_config reads for every application. This is where personal settings belong. - Bundled defaults,
lib/runsheets/config/defaults.ymlinside the gem. That file is the list of settings and documents each one.
Config files are flat YAML, one key per setting. Paths may start with
~ and relative paths are taken from the current directory. Flags are on
for 1, true, yes or on (any case) and off for any other value, so
RUNSHEETS_OPEN=off switches off an open: true in the file, and
--no-open switches off either. A blank value (RUNSHEETS_PORT=) counts as
unset. A port that is not a whole number from 1 to 65535, a log level
that is not one of the five (in any case: WARN is warn), a named
config file that does not exist, a config file that is not valid YAML, a
--bind host that does not resolve, or a runbook directory that cannot
be read is reported in one line and the command exits 1:
# ~/.config/runsheets/runsheets.yml
dir: ~/ops/runbooks/db-refresh
port: 4580
runs_dir: ~/ops/runs
open: true
With that file, plain runsheets serves the db-refresh runbook on port 4580
and opens the browser; runsheets --check checks it instead; and
RUNSHEETS_PORT=4581 runsheets or runsheets -p 4581 moves it for one run. A
repository can carry its own config/runsheets.yml (say dir: and
runs_dir:) that applies whenever runsheets is run from its root. One
thing it cannot do is open the server to the network: a non-loopback
bind: set only by that file stops the start with
runsheets: ./config/runsheets.yml sets bind: 0.0.0.0, which is not a loopback address….
Pass --bind or set RUNSHEETS_BIND if that is really wanted.
| Variable | Effect |
|---|---|
RUNSHEETS_CONFIG |
The file read in place of ./config/runsheets.yml, when --config is not given. |
RUNSHEETS_<SETTING> |
The setting of that name, as above. |
RACK_ENV |
Selects an environment section (development, test, production) in defaults.yml; none is required. |
PORT |
Not used. Set RUNSHEETS_PORT or pass --port. |
| anything else | Inherited by every executed block, and used to pre-fill inputs of the same name. See Inputs and Secrets. |
Saving settings¶
--dump prints the settings in force, after every layer has been applied,
in the shape of a config file, and exits. Redirect it to save them. Run it
with the options you want to keep and they become the defaults for later
runs:
runsheets --dump -p 4580 ~/ops/runbooks/db-refresh # look first
runsheets --dump -p 4580 ~/ops/runbooks/db-refresh > ~/.config/runsheets/runsheets.yml
runsheets # now serves db-refresh on 4580
Redirect to config/runsheets.yml instead for a project config to commit
with a repository. dump itself is never in the output, so a saved file
cannot make every later run print and exit, and neither are check and
init, for the same reason. Nor is why: the reason for a session
belongs to that session, not to every later one. engineer is saved.
About --bind¶
The default binds to loopback and the server only accepts requests whose
Host header is localhost, 127.0.0.1, ::1 or the bind address. That
is the whole multi-user story: there is none. Binding to another address
exposes shell execution on your machine to whoever can reach that address,
protected only by the session token embedded in the pages. Do not do it on
a network you do not control. The command prints a warning whenever the
bind address is not loopback. A wildcard address (0.0.0.0 or ::)
answers on every interface, so the Host check is turned off for it; a
specific address accepts requests for itself and the loopback names.
The session¶
Everything from start to stop is one session, belonging to one engineer
and opened with a note saying why (see
Sessions, Runs and Runsheets). The engineer and the
reason come from --engineer and --why, RUNSHEETS_ENGINEER and
RUNSHEETS_WHY, or engineer: and why: in a config file. With both
set, the session starts as the server does. Otherwise the browser opens on
a start page that asks for them, with the name pre-filled from the
configured engineer, else git config user.name, else $USER. The name
is taken as given; nothing authenticates it.
At start, any earlier session in the same runs directory that is still
marked running but whose process is gone is closed as interrupted,
along with its runs.
The session log¶
Every session writes session.log in its directory under
<runs-dir>/sessions/ (see
The Run Record). log_level sets what goes
into it:
| Level | What is logged |
|---|---|
debug |
Everything in the rows below, plus page views and other requests, searches, polling, runbook reloads, and the environment handed to each execution, secrets shown as [secret]. |
info |
Every action and its output: the session starting and ending, notes, a run opened with its inputs, inputs changed, each execution with its code and output, exit 0, stop requested, stopped, step marks and terminal confirmations with their notes. The default. |
warn |
Non-zero exits, timeouts, refused actions (a destructive block without its code or with the wrong one, any other action refused with 409), authoring warnings when a run opens, and an earlier session found interrupted. |
error |
An execution that cannot start, a runbook that no longer loads, an exception in the server. |
fatal is accepted too; runsheets writes nothing at that level, so it
leaves the file empty.
The log is echoed to the terminal that started runsheets, at info
whatever the file's level, unless --quiet, RUNSHEETS_QUIET or
quiet: true turns the echo off. Secret values never reach the log.
Stopping¶
Ctrl-C ends the session and stops the server, exactly like End session
on the session page. Every run is closed with a status worked out from what
was done (completed, partial or opened), anything still running in
any runbook (a background block, a block that was still going) is
stopped, and the records are written, so nothing outlives the tool and no
record is left saying running. If the process is killed instead, the
next start closes its session as interrupted.