microsoft / microsoft/skill-recorder
Terminal capture: use a recorded-terminal (PTY) approach, not a global shell hook
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 4k
- Forks
- 412
- Avg merge
- 3h 16m
- Merged PRs (30d)
- 10
Description
Context
The original terminal-capture feature installed a persistent shell hook (zsh preexec/precmd, bash DEBUG trap + PROMPT_COMMAND, pwsh prompt) into the user's profile. That hook appended one record per command to ~/.skill-recorder/shell.jsonl. The TerminalCollector tailed that file during a recording.
We removed that implementation because, evaluated honestly, its ROI was negative for our current audience (mostly non-technical users, where terminal work is uncommon):
- Always-on, not recording-scoped. Once installed, the hook wrote on every command in every interactive shell, forever — even when the app wasn't running.
- Per-prompt overhead. ~10ms/command measured on a dev Mac (it forked
date, twobase64, twotr, plus a file append every prompt). - Security liability. A permanent, unbounded, base64 (not encrypted) log of every command — including secrets typed inline (
export TOKEN=…,curl -H "Authorization: …"). - Fragility. The pwsh hook replaced the
promptfunction outright, clobbering Starship/oh-my-posh/p10k. Install also required opening a new shell to take effect (confusing). - Redundant. The describer already reads screen frames (
list_frames/get_frames, incl. region crop + higher-fps resample), so on-screen terminal work is already legible via video. Terminal window titles are also captured cross-platform with no hook.
Proposed approach when we revisit this: recorded terminal (PTY)
Model it on asciinema / script, not a global keylogger. During a recording, the app provides a terminal the user works in; only that session is captured.
- Embedded terminal pane (xterm.js) backed by
node-ptyrunning the user's shell, shown next to the record controls. - Inject our command-capture hook only into that spawned shell via a temporary
ZDOTDIR(zsh) /bash --rcfile/ temp$PROFILE(pwsh) that chains the user's real config, so aliases/prompt/PATH still work and no dotfiles are edited. - Capture is session-scoped and in-memory / temp, deleted after analysis. Nothing global, nothing persisted forever.
- Emit the existing
terminal.commandevents (the describer vocabulary is intentionally retained), and optionally capture terminal output too (richer than video OCR).
Properties
- ✅ Zero dotfile edits, zero idle cost, nothing persisted globally, auto-gone when the recording ends.
- ✅ Cross-platform (
node-ptyon macOS + Windows). - ⚠️ Tradeoff: only commands run in the app's terminal are captured, not pre-existing terminal windows. Acceptable for a "start / do the work / stop" recorder.
Alternatives considered
- Gated global hook (keep hooks in the user's real shells, but guard with a recording sentinel → one builtin
test -fwhen idle; write to a session-scoped file; add atuin-style regex secret redaction; append to the pwsh prompt instead of replacing it). Keeps capture of the user's existing terminals, but still edits dotfiles and needs an uninstaller. Pick this only if capturing pre-existing terminal windows becomes a hard requirement. - OS-native audit (macOS Endpoint Security exec events, Windows Sysmon / PowerShell ScriptBlock logging). Most powerful but system-wide, always-on, and privileged (Apple-granted entitlement / admin / GPO). Overkill and worse for privacy in a consumer app. Rejected.
Acceptance criteria (future work)
-
node-pty-backed terminal available during a recording (embedded pane). - User's real shell config is chained via temp
ZDOTDIR/--rcfile/temp$PROFILE; no permanent dotfile changes. - Command records captured only for the recorded session, stored session-scoped, removed after analysis.
- Secret redaction (regex filter) before anything is persisted.
- Cross-platform verified on macOS + Windows.
References
- asciinema — PTY-wrapped session recording (docs.asciinema.org/how-it-works)
- Atuin — preexec/precmd hooks, SQLite storage,
history_filtersecret redaction - zsh
ZDOTDIR/bash --rcfilefor dotfile-free per-session hook injection
Removed in the accompanying PR; this issue tracks the safer re-introduction.
Ported from https://github.com/adilei/skill-recorder/issues/7 (originally opened by @adilei on 2026-07-25).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by locating TerminalCollector and the existing terminal.command event vocabulary, then trace the recording controls and describer integration. The work is done when a node-pty terminal is available during recording, chains the user's shell configuration without editing dotfiles, captures and redacts session commands, removes session data after analysis, and works on macOS and Windows.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- bash, electron, node.js, powershell, typescript, zsh
- Domain
- cli, desktop, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100