# 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`:

```bash
# ~/.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.
