msu-statusline-uninstall
Removal is two layers, and they are not the same request. Unwiring takes the line
out of the user's settings.json and deletes what the install wrote. Uninstalling
removes the plugin from Claude Code. Unwiring alone stops the line.
Uninstalling alone does not. MEASURED: claude plugin uninstall empties the registry
and enabledPlugins, and leaves the version directory under $CONFIG/plugins/cache/
in place with a .orphaned_at marker and its scripts still executable — which is
exactly what the launcher globs for, so the line goes on rendering. claude plugin disable leaves it just as intact. Neither one is a way to switch the status line off.
Unwire first, always. Uninstalling the plugin takes this skill with it, so the
order that looks equivalent ends with a status line still wired into the user's
settings and nothing left that knows how to remove it. Recovering means reinstalling
the plugin to get this skill back.
If the request does not say which layer it means, ask. "Remove the status line" is
usually the unwire; "uninstall the plugin" is both, in that order.
What the install left
All under CONFIG = ${CLAUDE_CONFIG_DIR:-$HOME/.claude}:
| Path |
What it is |
Removal |
settings.json → .statusLine |
what actually runs the line |
restored or deleted, step 1–2 |
$CONFIG/msu-statusline.sh |
copy of the plugin's launcher |
deleted, step 3 |
$CONFIG/msu-statusline.prev |
the status line configured before, verbatim — often absent |
read by step 2, gone by step 3 if it was ever written |
$CONFIG/msu-statusline.conf |
the user's settings |
kept unless they say otherwise, step 4 |
$CONFIG/msu-statusline.cache |
last notice read, with .cache.lock, .cache.attempted and .cache.failures beside it |
deleted, step 3 |
That is the whole of what the install wrote. The plugin's own files sit elsewhere, under
$CONFIG/plugins/cache/*/msu-statusline/, put there by Claude Code rather than by the
install — step 6's business, not step 3's.
Unwire
CONFIG=${CLAUDE_CONFIG_DIR:-$HOME/.claude}
S=$CONFIG/settings.json
Edit settings.json as JSON, never as text — this path deletes a key, which is the
easier one to get wrong, and the file holds the user's permissions and hooks. Keep
its file mode while you do: the obvious atomic idiom, mktemp then mv, silently
replaces a 0644 file with a 0600 one. Clone the mode by making the temporary file a
copy of the original, which cp -p does and mktemp cannot:
S=$CONFIG/settings.json
cp -p "$S" "$S.new" && jq '<the edit>' "$S" > "$S.new" && mv -f "$S.new" "$S" \
|| { rm -f "$S.new"; exit 1; }
cp -p first, then the redirect: > truncates the copy and leaves its mode alone, and
mv over the original is atomic, so a jq that fails writes nothing. A failed edit
stops removal before any launcher, backup or cache is deleted.
Parsing and re-serialising reflows the file — every value survives, the formatting may
not. Expect a whole-file diff on a file the user may well be watching, and say so rather
than letting them find it.
Check the status line is still ours. Match .statusLine.command against
msu-statusline, not msu-statusline.sh: a command pointing straight into the
plugin at …/scripts/launcher.sh is still this plugin's, and a stricter match would
declare it the user's own and leave it running with no way to remove it.
msu-statusline-install matches on the same spelling when it decides what to
preserve, and the two have to agree.
A missing or empty settings file has no command to remove: skip to step 3 without
creating one. Stop on malformed JSON or a non-object root and keep the launcher and
backup intact until the settings can be read safely.
If it does not match, the user has changed their status line since installing.
Leave settings.json alone and say why, then skip to step 3 — restoring would
overwrite their newer choice.
Put back what was there. Which of the two branches below runs is the only real
decision on this path. Make it with the file rather than by eye — an emptied .prev
looks identical to a present one in a listing:
PREV=$CONFIG/msu-statusline.prev
if [ -e "$PREV" ] && [ ! -r "$PREV" ]; then
echo 'Cannot read the saved status line; keep the backup and stop.' >&2
exit 1
fi
previous=
if [ -f "$PREV" ]; then
previous=$(cat "$PREV") || exit 1
fi
case $previous in
*msu-statusline*) echo 'Saved command points back to MSU; it cannot be restored.' >&2
echo delete ;;
*[![:space:]]*) echo restore ;;
*) echo delete ;;
esac
Restore. Set .statusLine.command to what the file holds, and set
.statusLine.type to "command" rather than assuming it is already there — it is
the only type a command status line has, and the user's original may have gone
without it. Those two fields and no others: assigning a whole new statusLine object
would eat a padding the user set, on this branch exactly as on the one below.
Restore the file's bytes with jq --rawfile c "$PREV" and use $c for the command.
Command substitution strips trailing newlines, including ones the user's original
command deliberately contained. An older backup may include an extra newline; that
is valid shell syntax and does not need guessing away.
Keep padding and other siblings. Remove or restore refreshInterval only when the
conversation records what msu-statusline-config changed, or the user has requested
that change. .prev holds only the command, so an existing timer's ownership
cannot be inferred from the backup. Keep an unknown timer and report that it remains;
do not silently delete a schedule the user's own command may need.
Delete. No file, whitespace only, or a saved command that still names
msu-statusline: there is no usable previous command to put back. Restoring an MSU
command would point at the launcher step 3 deletes; never run that backup as a test.
Delete .statusLine.type, .statusLine.command and .statusLine.refreshInterval —
a timer with no command left to re-run does nothing. Then delete statusLine itself
only if nothing else is left inside it: a padding the user set is theirs, and
deleting the object whole takes it with no word said.
Report what the backup proves. A missing or emptied .prev only means no command
is available now; it does not prove the user ever had one or that install lost it.
If the backup was unusable, say why and offer to restore a command they can supply.
Delete $CONFIG/msu-statusline.sh and $CONFIG/msu-statusline.prev. Every file
deletion is here rather than split across step 2, so the skip in step 1 reaches them
too. .prev goes whichever branch ran, and whether it held a command or was emptied:
an emptied one is a state the troubleshooting tells users to create, and it would
outlive the thing that reads it. Delete the launcher copy whether or not it was the
one being run — a command pointing into the plugin means the launcher here was
already an orphan. A refresh may still be running: its lock is a directory, so
rm -f cannot remove it, and deleting it before the writer finishes lets that writer
recreate the cache after cleanup. After unwiring and deleting the launcher, allow
up to ten seconds for the refresh's eight-second network budget, then remove an
empty stale lock with rmdir. Stop and inspect a non-empty lock rather than recursively
deleting it. Remove only the known cache files, including an interrupted .cache.new:
rm -f "$CONFIG/msu-statusline.sh" "$CONFIG/msu-statusline.prev" || exit 1
for attempt in 1 2 3 4 5 6 7 8 9 10; do
[ -d "$CONFIG/msu-statusline.cache.lock" ] || break
sleep 1
done
if [ -d "$CONFIG/msu-statusline.cache.lock" ]; then
rmdir "$CONFIG/msu-statusline.cache.lock" || exit 1
fi
rm -f "$CONFIG/msu-statusline.cache" "$CONFIG/msu-statusline.cache.new" \
"$CONFIG/msu-statusline.cache.attempted" "$CONFIG/msu-statusline.cache.failures" \
|| exit 1
The conf file is the user's, so ask before deleting it. Keep
$CONFIG/msu-statusline.conf when only the status line is coming out — a reinstall
picks their settings back up — and say it is still there. Offer to delete it when the
plugin is going too; nothing else reads it.
A request that already asks for all of it — "remove everything" — is
that answer given in advance. Delete the conf and say you did, rather than offering
the user a choice they have already made.
Show that it worked, and that the restored command actually runs. bash -c, not
sh -c: the launcher ran it with bash, and on Debian and Ubuntu /bin/sh is dash,
which would fail a command that was working perfectly a minute ago. Feed it a session
JSON object rather than /dev/null — a status line that reads one prints nothing
without it, and the step looks like a failure.
CONFIG=${CLAUDE_CONFIG_DIR:-$HOME/.claude}
jq -n --arg dir "$PWD" '{model:{display_name:"Opus"},workspace:{current_dir:$dir}}' \
| bash -c "$(jq -r '.statusLine.command // empty' "$CONFIG/settings.json")"
Expect the user's own status line and nothing else. For a command that needs more
fields, use captured session JSON. Run this preview only after confirming the command
is non-empty and no longer names MSU; it also applies to a newer command kept in step 1.
On the delete branch that command proves nothing — // empty reduces it to
bash -c "", which cannot fail and would print nothing against a file you never
touched. Ask for the command instead of for the object: a padding the user set
keeps statusLine in the file quite legitimately, so its presence answers nothing.
jq '.statusLine.command' "$CONFIG/settings.json" # expect null
If the settings file was missing or empty, report that directly instead of running
jq against it and treating empty output as a parsed null.
Then say what changed and when. Settings reload automatically at the next
interaction with Claude Code; start a new session only if it has not updated.
See the Claude Code status-line guide.
Their own status line is the whole of it again if the restore branch
ran, or there is none at all if the delete branch did. msu-statusline.conf is still
there only if step 4 kept it. State whether the plugin is still installed based on
its actual state; unwiring does not install or enable a previously removed plugin.
Leave enabledPlugins alone here. Unwiring preserves the plugin's current install
and enablement state; step 6 lets the CLI remove the targeted entry itself.
Uninstall the plugin
Only when that is what was asked for, and only after the unwire above.
Uninstall it. Read claude plugin list --json first for the actual plugin ID
and installation scope. For the ordinary user-scope install from msu-skills, run
claude plugin uninstall msu-statusline@msu-skills --scope user -y
Use the reported marketplace suffix for a fork, and --scope project or
--scope local from the corresponding project directory when that is where it was
installed. Multiple scopes are separate installs: remove only the requested ones.
If it is already absent, there is nothing to uninstall. -y permits the CLI's
non-interactive path. Re-read the list to confirm that the targeted ID and scope are
gone; its enabled entry is removed from that scope's settings, not necessarily the
user settings file.
That uninstall rewrites settings.json itself, in its own key order — a second
reflow on top of step 2's. Expect it, and do not read it as an edit of yours that
went wrong.
Leave the msu-skills marketplace alone. The other plugins install from it, and
removing it is a separate request with a much wider blast radius. Same for
enabledPlugins entries that are not this plugin's.
The version directory under $CONFIG/plugins/cache/*/msu-statusline/ survives the
uninstall, marked .orphaned_at. claude plugin prune does not take it — that
removes auto-installed dependencies, and this is not one. Once step 1–3 have run,
nothing points at it and it is inert; delete it by hand if the user wants the disk
back, and say that a reinstall would fetch it again either way.
Add to what step 5 already told them. The plugin's skills go with it, this one
included, and a reinstall is what brings them back. Whether the conf file survived is
step 4's answer. Nothing else changes: step 5's message about the next interaction and about
which status line is left standing still holds.
Worth telling the user
- Turning every segment off is not removal.
NOTICE=off and the rest leave an
empty line still wired into settings.json. That is msu-statusline-config; this
skill is what takes the line out.
- A second status line that appeared at install is
.prev working as intended, not
a bug to remove the plugin over. Emptying $CONFIG/msu-statusline.prev drops the old
one and keeps the MSU line.
⚠ MSU statusline: plugin not found after an uninstall means the plugin went
first and the unwire never happened. The launcher copy is still in settings.json
with nothing left to resolve. Run steps 1–3 by hand, or reinstall the plugin and use
this skill.
Installing and repairing belong to msu-statusline-install; segments and polling to
msu-statusline-config.
1---2name: msu-statusline-uninstall3description: Claude Code only — a status line is a Claude Code concept and this skill does nothing on another CLI. Takes the MSU status line back out, restores whatever status line was there before it, and uninstalls the plugin when that is what was asked for. Use when the user wants to remove, uninstall, delete, disable or get rid of the MSU status line or the msu-statusline plugin, wants their old status line back, or asks what the install left on their machine.4---56# msu-statusline-uninstall78Removal is two layers, and they are not the same request. **Unwiring** takes the line9out of the user's `settings.json` and deletes what the install wrote. **Uninstalling**10removes the plugin from Claude Code. Unwiring alone stops the line.1112Uninstalling alone does not. MEASURED: `claude plugin uninstall` empties the registry13and `enabledPlugins`, and leaves the version directory under `$CONFIG/plugins/cache/`14in place with a `.orphaned_at` marker and its scripts still executable — which is15exactly what the launcher globs for, so the line goes on rendering. `claude plugin16disable` leaves it just as intact. Neither one is a way to switch the status line off.1718**Unwire first, always.** Uninstalling the plugin takes this skill with it, so the19order that looks equivalent ends with a status line still wired into the user's20settings and nothing left that knows how to remove it. Recovering means reinstalling21the plugin to get this skill back.2223If the request does not say which layer it means, ask. "Remove the status line" is24usually the unwire; "uninstall the plugin" is both, in that order.2526## What the install left2728All under `CONFIG` = `${CLAUDE_CONFIG_DIR:-$HOME/.claude}`:2930| Path | What it is | Removal |31|---|---|---|32| `settings.json` → `.statusLine` | what actually runs the line | restored or deleted, step 1–2 |33| `$CONFIG/msu-statusline.sh` | copy of the plugin's launcher | deleted, step 3 |34| `$CONFIG/msu-statusline.prev` | the status line configured before, verbatim — often absent | read by step 2, gone by step 3 if it was ever written |35| `$CONFIG/msu-statusline.conf` | the user's settings | kept unless they say otherwise, step 4 |36| `$CONFIG/msu-statusline.cache` | last notice read, with `.cache.lock`, `.cache.attempted` and `.cache.failures` beside it | deleted, step 3 |3738That is the whole of what the install wrote. The plugin's own files sit elsewhere, under39`$CONFIG/plugins/cache/*/msu-statusline/`, put there by Claude Code rather than by the40install — step 6's business, not step 3's.4142## Unwire4344```bash45CONFIG=${CLAUDE_CONFIG_DIR:-$HOME/.claude}46S=$CONFIG/settings.json47```4849Edit `settings.json` as JSON, never as text — this path *deletes* a key, which is the50easier one to get wrong, and the file holds the user's permissions and hooks. **Keep51its file mode** while you do: the obvious atomic idiom, `mktemp` then `mv`, silently52replaces a 0644 file with a 0600 one. Clone the mode by making the temporary file a53copy of the original, which `cp -p` does and `mktemp` cannot:5455```bash56S=$CONFIG/settings.json57cp -p "$S" "$S.new" && jq '<the edit>' "$S" > "$S.new" && mv -f "$S.new" "$S" \58 || { rm -f "$S.new"; exit 1; }59```6061`cp -p` first, then the redirect: `>` truncates the copy and leaves its mode alone, and62`mv` over the original is atomic, so a `jq` that fails writes nothing. A failed edit63stops removal before any launcher, backup or cache is deleted.6465Parsing and re-serialising reflows the file — every value survives, the formatting may66not. Expect a whole-file diff on a file the user may well be watching, and say so rather67than letting them find it.68691. **Check the status line is still ours.** Match `.statusLine.command` against70 `msu-statusline`, not `msu-statusline.sh`: a command pointing straight into the71 plugin at `…/scripts/launcher.sh` is still this plugin's, and a stricter match would72 declare it the user's own and leave it running with no way to remove it.73 `msu-statusline-install` matches on the same spelling when it decides what to74 preserve, and the two have to agree.7576 A missing or empty settings file has no command to remove: skip to step 3 without77 creating one. Stop on malformed JSON or a non-object root and keep the launcher and78 backup intact until the settings can be read safely.7980 If it does **not** match, the user has changed their status line since installing.81 Leave `settings.json` alone and say why, then skip to step 3 — restoring would82 overwrite their newer choice.832. **Put back what was there.** Which of the two branches below runs is the only real84 decision on this path. Make it with the file rather than by eye — an emptied `.prev`85 looks identical to a present one in a listing:8687 ```bash88 PREV=$CONFIG/msu-statusline.prev89 if [ -e "$PREV" ] && [ ! -r "$PREV" ]; then90 echo 'Cannot read the saved status line; keep the backup and stop.' >&291 exit 192 fi93 previous=94 if [ -f "$PREV" ]; then95 previous=$(cat "$PREV") || exit 196 fi97 case $previous in98 *msu-statusline*) echo 'Saved command points back to MSU; it cannot be restored.' >&299 echo delete ;;100 *[![:space:]]*) echo restore ;;101 *) echo delete ;;102 esac103 ```104105 **Restore.** Set `.statusLine.command` to what the file holds, and set106 `.statusLine.type` to `"command"` rather than assuming it is already there — it is107 the only type a command status line has, and the user's original may have gone108 without it. Those two fields and no others: assigning a whole new `statusLine` object109 would eat a `padding` the user set, on this branch exactly as on the one below.110 Restore the file's bytes with `jq --rawfile c "$PREV"` and use `$c` for the command.111 Command substitution strips trailing newlines, including ones the user's original112 command deliberately contained. An older backup may include an extra newline; that113 is valid shell syntax and does not need guessing away.114115 Keep `padding` and other siblings. Remove or restore `refreshInterval` only when the116 conversation records what `msu-statusline-config` changed, or the user has requested117 that change. **`.prev` holds only the command**, so an existing timer's ownership118 cannot be inferred from the backup. Keep an unknown timer and report that it remains;119 do not silently delete a schedule the user's own command may need.120121 **Delete.** No file, whitespace only, or a saved command that still names122 `msu-statusline`: there is no usable previous command to put back. Restoring an MSU123 command would point at the launcher step 3 deletes; never run that backup as a test.124 Delete `.statusLine.type`, `.statusLine.command` and `.statusLine.refreshInterval` —125 a timer with no command left to re-run does nothing. Then delete `statusLine` itself126 only if nothing else is left inside it: a `padding` the user set is theirs, and127 deleting the object whole takes it with no word said.128129 **Report what the backup proves.** A missing or emptied `.prev` only means no command130 is available now; it does not prove the user ever had one or that install lost it.131 If the backup was unusable, say why and offer to restore a command they can supply.1321333. **Delete `$CONFIG/msu-statusline.sh` and `$CONFIG/msu-statusline.prev`.** Every file134 deletion is here rather than split across step 2, so the skip in step 1 reaches them135 too. `.prev` goes whichever branch ran, and whether it held a command or was emptied:136 an emptied one is a state the troubleshooting tells users to create, and it would137 outlive the thing that reads it. Delete the launcher copy whether or not it was the138 one being run — a command pointing into the plugin means the launcher here was139 already an orphan. A refresh may still be running: its lock is a **directory**, so140 `rm -f` cannot remove it, and deleting it before the writer finishes lets that writer141 recreate the cache after cleanup. After unwiring and deleting the launcher, allow142 up to ten seconds for the refresh's eight-second network budget, then remove an143 empty stale lock with `rmdir`. Stop and inspect a non-empty lock rather than recursively144 deleting it. Remove only the known cache files, including an interrupted `.cache.new`:145146 ```bash147 rm -f "$CONFIG/msu-statusline.sh" "$CONFIG/msu-statusline.prev" || exit 1148 for attempt in 1 2 3 4 5 6 7 8 9 10; do149 [ -d "$CONFIG/msu-statusline.cache.lock" ] || break150 sleep 1151 done152 if [ -d "$CONFIG/msu-statusline.cache.lock" ]; then153 rmdir "$CONFIG/msu-statusline.cache.lock" || exit 1154 fi155 rm -f "$CONFIG/msu-statusline.cache" "$CONFIG/msu-statusline.cache.new" \156 "$CONFIG/msu-statusline.cache.attempted" "$CONFIG/msu-statusline.cache.failures" \157 || exit 1158 ```1594. **The conf file is the user's, so ask before deleting it.** Keep160 `$CONFIG/msu-statusline.conf` when only the status line is coming out — a reinstall161 picks their settings back up — and say it is still there. Offer to delete it when the162 plugin is going too; nothing else reads it.163164 A request that already asks for all of it — "remove everything" — is165 that answer given in advance. Delete the conf and say you did, rather than offering166 the user a choice they have already made.1675. **Show that it worked**, and that the restored command actually runs. `bash -c`, not168 `sh -c`: the launcher ran it with bash, and on Debian and Ubuntu `/bin/sh` is dash,169 which would fail a command that was working perfectly a minute ago. Feed it a session170 JSON object rather than `/dev/null` — a status line that reads one prints nothing171 without it, and the step looks like a failure.172173 ```bash174 CONFIG=${CLAUDE_CONFIG_DIR:-$HOME/.claude}175 jq -n --arg dir "$PWD" '{model:{display_name:"Opus"},workspace:{current_dir:$dir}}' \176 | bash -c "$(jq -r '.statusLine.command // empty' "$CONFIG/settings.json")"177 ```178179 Expect the user's own status line and nothing else. For a command that needs more180 fields, use captured session JSON. Run this preview only after confirming the command181 is non-empty and no longer names MSU; it also applies to a newer command kept in step 1.182183 **On the delete branch that command proves nothing** — `// empty` reduces it to184 `bash -c ""`, which cannot fail and would print nothing against a file you never185 touched. Ask for the command instead of for the object: a `padding` the user set186 keeps `statusLine` in the file quite legitimately, so its presence answers nothing.187188 ```bash189 jq '.statusLine.command' "$CONFIG/settings.json" # expect null190 ```191192 If the settings file was missing or empty, report that directly instead of running193 `jq` against it and treating empty output as a parsed `null`.194195 **Then say what changed and when.** Settings reload automatically at the next196 interaction with Claude Code; start a new session only if it has not updated.197 See the [Claude Code status-line guide](https://code.claude.com/docs/en/statusline).198 Their own status line is the whole of it again if the restore branch199 ran, or there is none at all if the delete branch did. `msu-statusline.conf` is still200 there only if step 4 kept it. State whether the plugin is still installed based on201 its actual state; unwiring does not install or enable a previously removed plugin.202203**Leave `enabledPlugins` alone here.** Unwiring preserves the plugin's current install204and enablement state; step 6 lets the CLI remove the targeted entry itself.205206## Uninstall the plugin207208Only when that is what was asked for, and only after the unwire above.2092106. **Uninstall it.** Read `claude plugin list --json` first for the actual plugin ID211 and installation scope. For the ordinary user-scope install from `msu-skills`, run212213 ```bash214 claude plugin uninstall msu-statusline@msu-skills --scope user -y215 ```216217 Use the reported marketplace suffix for a fork, and `--scope project` or218 `--scope local` from the corresponding project directory when that is where it was219 installed. Multiple scopes are separate installs: remove only the requested ones.220 If it is already absent, there is nothing to uninstall. `-y` permits the CLI's221 non-interactive path. Re-read the list to confirm that the targeted ID and scope are222 gone; its enabled entry is removed from that scope's settings, not necessarily the223 user settings file.224225 That uninstall rewrites `settings.json` itself, in its own key order — a second226 reflow on top of step 2's. Expect it, and do not read it as an edit of yours that227 went wrong.228229 **Leave the `msu-skills` marketplace alone.** The other plugins install from it, and230 removing it is a separate request with a much wider blast radius. Same for231 `enabledPlugins` entries that are not this plugin's.232233 The version directory under `$CONFIG/plugins/cache/*/msu-statusline/` survives the234 uninstall, marked `.orphaned_at`. `claude plugin prune` does not take it — that235 removes auto-installed dependencies, and this is not one. Once step 1–3 have run,236 nothing points at it and it is inert; delete it by hand if the user wants the disk237 back, and say that a reinstall would fetch it again either way.2387. **Add to what step 5 already told them.** The plugin's skills go with it, this one239 included, and a reinstall is what brings them back. Whether the conf file survived is240 step 4's answer. Nothing else changes: step 5's message about the next interaction and about241 which status line is left standing still holds.242243## Worth telling the user244245- **Turning every segment off is not removal.** `NOTICE=off` and the rest leave an246 empty line still wired into `settings.json`. That is `msu-statusline-config`; this247 skill is what takes the line out.248- **A second status line that appeared at install is `.prev` working as intended**, not249 a bug to remove the plugin over. Emptying `$CONFIG/msu-statusline.prev` drops the old250 one and keeps the MSU line.251- **`⚠ MSU statusline: plugin not found` after an uninstall** means the plugin went252 first and the unwire never happened. The launcher copy is still in `settings.json`253 with nothing left to resolve. Run steps 1–3 by hand, or reinstall the plugin and use254 this skill.255256Installing and repairing belong to `msu-statusline-install`; segments and polling to257`msu-statusline-config`.