Known shell-configuration interactions

cin90 start runs your own shell, with your own configuration, and adds a small amount of its own. This is the list of places where that addition is visible, or where a shell's own setup can prevent it from working.

It exists because docs/decisions/0001-executed-command-capture.md requires it: the --rcfile caveat below is described there as "a real 'cin90 broke my shell' report waiting to happen", and a caveat nobody wrote down is one nobody can act on.

Nothing here is a workaround you have to apply. It is what to look at when a session behaves differently from the shell you are used to.

bash

--rcfile governs non-login interactive shells only. cin90 starts bash with --rcfile, which makes bash read cin90's file instead of ~/.bashrc — and cin90's file sources ~/.bashrc first, so ordinarily nothing changes.

What it does not read is ~/.bash_profile, ~/.profile or ~/.bash_login. Those are login-shell files, and a --rcfile shell is not a login shell.

If your environment lives in .bash_profile — a PATH entry, a pyenv or nvm initialisation, a PS1 — a cin90 session will not have it, and the symptom is "my tools are missing inside cin90". The usual arrangement, and the one most guides recommend anyway, is for .bash_profile to source .bashrc:

shell
# ~/.bash_profile
[ -f ~/.bashrc ] && . ~/.bashrc

HISTCONTROL is rewritten for the session. cin90 uses the vendored bash-preexec, which strips ignorespace so that space-prefixed commands stay visible to history 1 — the mechanism it reads command text from. Measured on bash 3.2.57 and 5.2.21: ignoreboth becomes ignoredups:.

If you deliberately set ignorespace to keep commands out of your history, that does not apply inside a cin90 session. The before and after values are recorded in the session's own metadata, so the change is visible rather than mysterious.

bash 3.2 (stock macOS) loses heredoc bodies. history 1 never receives them, so cat <<EOF … EOF is captured as cat <<EOF — and cin90 marks that text truncated rather than reporting it as the whole command. A homebrew bash 5 does not have the problem. Multi-line commands are stored by bash in its own semicolon-joined form on every version, which is the same command written differently rather than a loss.

bash 3.2 also has no sub-second clock, so timestamps are whole seconds and each command costs one date fork (measured: 5.9–9.0 ms per prompt). bash 5 has EPOCHREALTIME and pays neither cost.

zsh

ZDOTDIR is taken over for the length of startup, then handed back. cin90 points ZDOTDIR at its own directory so its four dotfiles run, and each of them sources yours first. At the end of .zshrc (and .zlogin) the variable is put back exactly as you had it — including unset, if that is how it was.

If your own .zshenv sets ZDOTDIR — the standard XDG arrangement, ZDOTDIR=$HOME/.config/zsh — cin90 follows it: your dotfiles keep being sourced from where you keep them, and ZDOTDIR is re-pinned afterwards so the rest of startup still reaches cin90's hooks. This is the same layout VS Code's shell integration uses. Child shells you start inside the session see your value.

Your prompt hooks keep working. cin90 registers with add-zsh-hook, which appends, so nothing of yours is replaced. Its precmd entry is then moved to the front of precmd_functions, because zsh runs them in order and any command a hook runs destroys $? before a later hook could read it. Every one of your hooks still runs, in its original order relative to the others.

Both shells

A command backgrounded with & records no exit code. $? immediately after a background launch is the launch status, not the job's, so cin90 reports the exit code as unavailable rather than claiming a success nobody observed.

Anything that stops cin90's rc from running disables capture for the session — and says so. The session records the command log as unavailable rather than empty, because "we could not see" and "you ran nothing" are different claims and only one of them is true.

A shell that is not bash or zsh still runs. cin90 does not refuse to start and does not substitute a different shell; capture reports unavailable for the whole session. fish is not supported in v1.

Where to look when something is off

Every session writes its own record under .cin90/sessions/<id>/session.json in the assignment repository. The shell and capture blocks there name the shell, its version, where its timestamps came from, and — if capture degraded — what happened, in words.

Read this page in your terminal: install the cin90 CLI and run cin90 docs. The same page is served as raw markdown.