Skip to main content
Session recording keeps a replayable record of what happened in a sandboxed session’s terminal: the output, the input sent to it, and terminal facts such as window size, terminal mode, the foreground process, and notifications. The recording is stored with the session’s audit trail and linked into its hash-chained event log, so nono audit verify can show that it has not been changed. Recording is off by default. Turn it on with a profile or a launch flag.
When recording is on, the session starts with a one-line notice on the terminal (or on stderr when there is no terminal). A detached session shows it when it is launched, and nono attach shows it to everyone who joins. Profiles and --silent cannot suppress it.

Watching and reading recordings

Sessions can be named by ID, ID prefix or name.
  • Replay draws the recorded terminal through a terminal model. Sequences an agent printed that act on your terminal itself, such as clipboard writes, window titles or mode changes, are not passed on. A session recorded in a larger terminal than yours is shown from its top-left corner, cut to fit your terminal; enlarge the terminal, even during the replay, or use nono transcript to see all of it. Press Ctrl-C to stop.
  • Transcript prints text that scrolled by once, in order. A screen that was redrawn in place, such as a full-screen interface, is shown as it stood at pauses. It also notes when the session was suspended or ended, when password input was not recorded, and which credentials were too short to remove.
  • Both refuse a recording that does not match the audit log. nono audit verify reports missing or altered chunks, and gaps in the recording that no recorded loss explains.

What is protected

Two protections always apply. They have no settings and cannot be turned off.
  • Known credentials are removed. Credential values nono resolved for the session are replaced with [redacted:credential:<name>] in both output and input. This covers proxy-injected credentials, credentials loaded into the environment from keyrings or providers, and credential capture outputs, as well as tokens nono refreshes during the session. Values are also matched base64-encoded and percent-encoded, and when they are split across reads, however long the pause between the pieces. Values shorter than 8 bytes are not matched; their names (never their values) are listed in the recording so the gap is visible.
  • Password input is never recorded. While the terminal is in canonical mode with echo off, which is how sudo, ssh and getpass(3) read passwords, nono records only that input was typed, not what or how much. Full-screen agent interfaces also turn echo off, but in raw mode, so their input is recorded normally.
Recording removes only what nono knows. Secrets that nono never held can still appear in a recording, so treat recordings as sensitive.

Where recordings are stored

Recordings are written to the session’s audit directory, under $XDG_STATE_HOME/nono/audit/<session>/terminal/, which the sandbox cannot read or write. The recording is a series of zstd-compressed asciicast v2 chunks. Each chunk closes after 10 seconds, at 1 MiB, when the session is suspended, or when it ends, and each closed chunk is recorded in the audit log with its SHA-256. Recording needs the audit log and the supervisor. The recording flags are rejected together with --no-audit. When a profile turns recording on but the session runs with --no-audit or under nono wrap, a required recording refuses to start, and an optional one is skipped with a warning.

Profile settings

Settings can only be raised. A profile that extends another, and the launch flags, can turn recording on, make it required, turn input recording on, raise max_bytes, or add a destination, but they cannot undo what a base profile set. For example, enabled: false in a child profile has no effect when its base sets enabled: true.

Launch flags

The flags are accepted by nono run and nono shell.

Required recording

When recording is required, nono fails closed:
  • If recording cannot start, the agent does not run.
  • If recording fails while the session is running, for example because the disk is full or the recording reached max_bytes, nono stops the session.
  • If the recording is incomplete when the session ends, nono exits with status 74, even if the agent succeeded, so a pipeline sees the failure.
When recording is not required, a failure is recorded in the audit log and the session carries on.

Writing a copy for artifact collection

file and --record-file write a copy of the recording to a path outside the sandbox, for hosts that collect job artifacts. The copy is a playable .cast file. Next to it, <file>.manifest.json lists each chunk with the hash recorded in the audit log and the hash of the bytes it added to the copy. The manifest is kept current while the session runs.
  • Relative paths resolve against the directory nono was launched from. $WORKDIR and ~ are expanded in profile paths.
  • Both files are created when the session starts and must not already exist. nono never overwrites a file or writes through a symlink.
  • file is honoured only in the profile you select, and only when you authored it (a user profile or a profile given by path). A file inherited through extends is ignored, as is one in a package, registry or built-in profile; recording stays on without the copy.
  • A profile can set one file, and --record-file adds another.
The copy in the audit directory remains the authoritative recording.

Delivering recordings to the platform

On a host enrolled with a platform (nono platform enroll), recordings can be uploaded as they are made:
or --deliver-to platform for a single run.
  • Each chunk is uploaded when it closes, signed with the host’s enrollment key, so the platform can show a running session about 10 seconds behind.
  • Upload never slows the session down. Failed uploads are retried, and at session end nono waits up to flush_timeout_secs for what is left.
  • With required: true, the session does not start unless the host is enrolled, and nono exits with status 74 if any chunk could not be delivered. It also makes the recording itself required.
  • The platform treats uploaded chunks as unverified until the session’s audit log arrives and matches them.
  • The only receiver so far is platform. Chunks that were not delivered stay in the local recording.
The wire format is specified in the recording delivery protocol.

Current limits

  • Only sessions with a terminal are recorded.
  • Input from nono attach clients is attributed as attach:<n>.