# shellrec — Changelog

## v1.0.0 — 2026-06-25

Initial release. Fifth tool in the "productivity-boost" series.

### Purpose

Forensic-quality recording of a CLI session with cryptographic
chain-of-custody. The use case is the regulated-incident path: when
an operator runs a privileged remediation step in the middle of an
ICT incident (DORA Art. 17 / NIS2 Art. 23), the regulator wants
something better than `script(1)` — a tamper-evident artefact that
ties the session to a specific operator and a specific keypair.

### Subcommands

```
shellrec record [--out FILE] [--cols N] [--rows N] [--capture-stdin] [cmd…]
shellrec play   <FILE>  [--speed S] [--max-idle-ms MS] [--no-timing]
shellrec transcript <FILE> [-o OUT]
shellrec sign   <FILE>  [--key SECFILE]
shellrec verify <FILE>
shellrec list
shellrec info   <FILE>  [-F human|json|jfind]
```

### File format (shellrec/v1, NDJSON)

```
{"schema":"shellrec/v1","kind":"header","session_id":…,"started_at":…,"user":…,"host":…,"cwd":…,"command":[…],"cols":…,"rows":…,"tool_version":…}
{"kind":"out","t_ms":N,"d":"…utf8…"}              # or "b64":"…" for binary
{"kind":"in", "t_ms":N,"d":"…"}                   # only with --capture-stdin
{"kind":"footer","t_ms":N,"exit":N,"events":N,"bytes":N}
{"kind":"sig","alg":"ed25519","pubkey_hex":…,"sig_hex":…,"sha256_hex":…}
```

The signature covers everything *before* the `sig` line — appending
after signing invalidates the signature. SHA-256 of the same bytes is
embedded in the sig line as a redundant integrity anchor (verifiable
without the public key).

### Key management

On first `sign` we generate an Ed25519 keypair under:
- `$XDG_DATA_HOME/cli-johlem/shellrec/keys/shellrec-ed25519.sec` (0600)
- `$XDG_DATA_HOME/cli-johlem/shellrec/keys/shellrec-ed25519.pub`

Format is deliberately *not* signify-compatible — we skip the
passphrase prompt because the chain-of-custody value comes from the
keypair binding, not from operator memory. Operators who want the
signify workflow can pass `--key /path/to/sec` on every `sign` /
`verify` call.

### jfind/v1 output

`info -F jfind` emits one record per session:

| `verified` | Category | Severity |
|---|---|---|
| `Some(true)`  (signed + verified) | `asset-inventory` | Info |
| `None`        (unsigned)          | `asset-inventory` | Info |
| `Some(false)` (verify failed)     | `policy-violation` | High |

Pre-fills DORA Art. 12 (ICT-related incident management — evidence
retention) + DORA Art. 17 (incident reporting evidence basis) + NIS2
Art. 23 + ISO/IEC 27001:2022 A.5.28.

### Exit codes

```
0  ok
2  usage (clap)
3  runtime (io, pty, key, parse)
4  signature verification failed (verify subcommand, or double-sign refused)
```

### Build

- Library crate + thin CLI binary.
- 4 unit + 13 integration tests = 17 tests, all green.
- Zero compiler warnings.
- PTY via `portable-pty 0.8`.
- Ed25519 via `ed25519-dalek 2`.
- ANSI strip via `strip-ansi-escapes 0.2`.
- SHA-256 cross-check via `sha2 0.10`.
- Offline-only; no network access.
- Suite-standard exit codes + tagline footer.
- NixOS-only platform gate in `install.sh`.

### Suite interop

| Producer | Consumer | Use case |
|---|---|---|
| operator | shellrec | record an incident-remediation session |
| shellrec | dossier  | attach a session to an incident report |
| shellrec | inciclass | reference the session in DORA Art. 17 notification |
| shellrec | complymap | session existence as evidence of A.5.28 control |
| shellrec | notify    | post the session-signed jfind line to Slack |

### Deferred to v1.1

- SIGWINCH propagation (PTY stays at the initial size).
- Operator-side raw-mode shimming for fully interactive recording
  (today: the inner PTY is real, but the operator's tty is still in
  cooked mode).
- `--encrypt` for at-rest encryption of the recording body.
- `merge` / `slice` operations on existing recordings.
- asciinema-format export.
- A `verify --strict` flag that requires the recording to be signed
  by a key in a pinned allowlist file.
